1

I am having strange behavior with a client server image transfer. Currently the server always stalls when it has read 32768 bytes out of the buffer, the total file size is 36556 bytes. The while loop does not end, yet it doesn't print any of the print statements inside of it, and there are no exceptions thrown. I have tried several different size byte buffers and even going larger than the image size does not solve the issue.

Client Code:

private static void writePhoto(Socket socket) throws IOException {

    OutputStream outputStream = new   BufferedOutputStream(socket.getOutputStream());

    String file_path = "E:\\Eclipse\\Workspace\\DNI_PsuedoClient\\" +
            "src\\main\\resources\\BuckyBadger.jpg";
    try {
        InputStream stream = new FileInputStream(file_path);
        System.out.println(stream.available());
        try {
            byte[] buffer = new byte[1024];
            int readData;
            int i = 1; 
            while((readData=stream.read(buffer))!=-1){
                System.out.println(readData + " " + i);
            outputStream.write(buffer,0,readData);
            i++;
            }
            System.out.println("done writing to buffer");
        }catch (IOException e) {
              System.err.println("File Error");
              e.printStackTrace();
              System.exit(-1);
        }finally {
            stream.close();
        }
    } finally {
    }
}

Server Code

private static java.io.File createFile(Socket client) throws IOException {

    System.out.println("Starting to create file");
    InputStream stream = new BufferedInputStream(client.getInputStream());

    System.out.println("1");
    // Create file from the inputStream
    java.io.File Recieved_File = new java.io.File(thread_ID + ".jpg");
    System.out.println(thread_ID + ".jpg");
    System.out.println("2");

    try {
       OutputStream outputStream = new FileOutputStream(Recieved_File);
       System.out.println("3");

       try {
          byte[] buffer = new byte[1024];
          System.out.println("4");
          int readData;
          int i = 1;

          while ((readData = stream.read(buffer)) != -1) {
              System.out.println("start");
              outputStream.write(buffer, 0, readData);
              System.out.println(readData + " " + i + " " + (i * readData));
              i++;
              System.out.println("end while loop");
          }
       } finally {
         System.out.println("5");
         outputStream.close();
         System.out.println("6");
         }
     } finally {
   }
   System.out.println("Created file");
   return Recieved_File;
}

As you can see I have made several attempts using print statements in the Server code to try to figure out the issue. Any insight would be extremely helpful.

For further reference I have had the exact same server code working for an interaction with a Windows phone where the phone took a photo and uploaded it to the server. I am now changing the code to run on multiple threads and testing it in Java first with a java client that is simulating the interaction. The java client is attempting to send a photo stored on the drive to the server. The client appears to be working correctly as it puts the entire photo into the buffer.

I have written a protocol, here it is:

public DNI_Protocol(Socket socket, String threadID) {
    client = socket;
    thread_ID = threadID;
}

public String processInput(String theInput) {

    String theOutput = null;
    if (state == WAITING) {
      System.out.println(theInput);
      if (theInput.equals("Upload")) {
        state = UPLOAD_PHOTO;
        theOutput = "Send Photo";
      } else if (theInput == "View") {
        state = VIEW;
        theOutput = "Send Request";
      } else {
        theOutput = "Waiting";
      }
    } else if (state == UPLOAD_PHOTO) {
      // if (theInput != "Sending Photo") {
      // TODO: Throw a state exception with a message
      // return "exit";
      // }
      setupDrive();
      try {
        Image_Handle = createFile(client);
        System.out.println("Uploading file");
        uploadedFile = Drive_Interface.uploadFile(false, Image_Handle, drive);
        System.out.println("file Uploaded");
        google_ID = uploadedFile.getId();
        System.out.println(google_ID);
        Image_Handle.delete(); // We are done with the file so we can delete it
        System.out.println("deleted file");
      } catch (IOException e) {
        e.printStackTrace();
      }
      theOutput = "Send Keywords";
      state = UPLOAD_KEYWORDS;
    } else if (state == UPLOAD_KEYWORDS) {
      if (theInput != "Sending Keywords") {
        // TODO: Throw a state exception with a message
        return "exit";
      }
      // TODO: Add code to get keyword arraylist and upload information to
      // the database
      theOutput = "exit";
    }
    return theOutput;
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
JME
  • 2,293
  • 9
  • 36
  • 56
  • 3
    What are you expecting to happen? Your code contains no way for the client to stop the server from continuing to wait for more data. So the server keeps waiting forever. (When you designed the protocol you used to communicate between these two programs, two questions you should have answered were "How will the client tell the server that it has the entire file?" and "How will the server know that it has the entire file?") Perhaps you meant to close the connection in the client? – David Schwartz Nov 15 '12 at 12:18
  • Had you tried calling `flush()`, with all instances of `Buffered` related Streams ? As I am not so good with `File Handling`, hence just a small idea i can give, to look at. – nIcE cOw Nov 15 '12 at 12:19
  • 1
    @GagandeepBali There's no explicit buffering, so the only buffering is the Nagle's algorithm, which doesn't introduce a long delay. – John Dvorak Nov 15 '12 at 12:22
  • @DavidSchwartz There is no way for me to tell the server that it has the entire file as the server while loop never reaches the total file size. As my edit mentions this exact same code worked previously when interacting with a Windows Phone application and now is giving me trouble when attempting to interact with a java client. – JME Nov 15 '12 at 12:27
  • 1
    You said the client put the entire file into the buffer. The next thing it needs to do is communicate to the server that is has done that somehow. It looks like you intended to do this by closing the socket. However, you have no way to know whether the server has read the whole file or not. Was the idea that the client would try to close the connection while the server might still be reading data? (Did you actually design a protocol? Because you should have worked out these issues before writing any code.) – David Schwartz Nov 15 '12 at 12:35
  • I can't close the socket because that would end the thread and there is more data that the client needs to hand to the server. What is curious is that if I make the buffersize to be the exact same size as the file the while loop still stalls completely, and as I have said it should at least be printing the statements inside of it if it was spinning but it is not. There is no further progress at all, no printstatements, or exceptions. – JME Nov 15 '12 at 12:39
  • @DavidSchwartz I do have a protocol, I have added it to the post. – JME Nov 15 '12 at 12:43
  • 2
    `(i * readData)` is wrong for a total. You need to keep a running total of the bytes as each read could return a different amount. – Brian White Nov 15 '12 at 12:45
  • 1
    Your protocol doesn't explain how the server knows when it has received the entire file. Your code provides no way for the server to know when it has received the entire file. Somehow, the client has to tell the server when it has received the entire file, either by sending the size of the file or by closing the connection. (Or by negotiating a undirectional shutdown of the TCP connection and then closing it, which is what the first version of HTTP does.) – David Schwartz Nov 15 '12 at 12:45
  • @David Schwartz I don't know how to explain this better because I don't think you understand. What I have been trying to explain is this. I am sending a file over a tcp connection. I have hard coded that it is expecting 36556 bytes of data. The server while loop reaches 32768 bytes of data then stops doing anything at all. The while loop does not appear to continue, no print statements appear, and the server does not continue in any fashion. The client i sends 35 1024 byte arrays and one ~700 byte array, the server stops at 32 1024 arrays and does nothing. – JME Nov 15 '12 at 12:50
  • @Brian White that line was meant to give me an exact file size, it was to give a rough estimate of what happens, it works correctly up until the last byte array sent. – JME Nov 15 '12 at 12:55
  • 1
    Your explanation conflicts with the actual code. Your server code says `while ((readData = stream.read(buffer)) != -1)`. That reads until the socket closes or errors. The server stops and does nothing because it has no code to do anything in this case. It just stays stuck in the `while` loop because the exit condition for the loop isn't met. (See my answer.) – David Schwartz Nov 15 '12 at 13:00

1 Answers1

4

Your server code says this:

      while ((readData = stream.read(buffer)) != -1) {
          System.out.println("start");
          outputStream.write(buffer, 0, readData);
          System.out.println(readData + " " + i + " " + (i * readData));
          i++;
          System.out.println("end while loop");
      }

This keeps reading from the socket until either the socket closes or the server gets an error, there are no other reasons read would return -1. Since neither of these conditions occur, the server stays in this while loop. You simply never wrote any code to handle the end of the file.

If the server knows it's going to read a particular number of bytes, it needs to break out of the while loop when it has read that number of bytes. If the client is going to tell the server that it has finished sending the file by closing the socket or shutting down one direction of the TCP connection, then the client needs code to do that. Otherwise, the server will wait forever.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • And if the while loop kept running indefinitely I would be able to tell due to both the "start" and "end while loop" print statements repeating over and over again. This does not occur. I have added code for the server to expect the 36556 byte file size and move on after reaching this point. The thing is it never reaches this point it stops at 32768 bytes, as I have said repeatedly, and does nothing more. – JME Nov 15 '12 at 13:21
  • To iterate on my point further. If I change the byte array size to 4096, and have the code set to expect 36556 bytes of data, the while loop still stalls at 32768 bytes. What I am trying to explain is that the code does not crash, but it also does not give me any repeated statements indicative of an infinite loop. Your solution solves for an infinite loop which I have no indication of. – JME Nov 15 '12 at 13:25
  • 1
    It doesn't exit the loop, what more do you need? – David Schwartz Nov 15 '12 at 13:31