1

I am writing a program to transfer files between two computers, but I am not closing the socket for I am using the same socket to transfer other messages (like transfer server's folders organization).

At a certain point, I have this code to transfer files from server to client:

Server

  System.out.println("Sending " + threadItem.second.getName() + " of " + threadItem.second.length() + "b");

  FileInputStream fileInputStream = new FileInputStream(threadItem.second);

  byte[] buffer = new byte[BLOCK_SIZE];

  int count;
  while ((count = fileInputStream.read(buffer)) > 0) {
      outputStream.write(buffer, 0, count);
  }

  outputStream.write(END_OF_STREAM, 0, 1);

  System.out.println("File sent.");

  fileInputStream.close();

And the client receives:

  FileOutputStream fOutputStream = new FileOutputStream(new File("./received/" + obj.toString()));
  byte[] buffer = new byte[4096];
  int count;

  while ((count = dataInputStream.read(buffer)) > 0 && !(buffer[count - 1] == '\0')) {
      fOutputStream.write(buffer, 0, count);
  }

  fOutputStream.close();

It works, but the real problem is when I send another message from server to client instants after this situation above :

Server

outputStream.writeUT(new JSONObject()
    .put("command", MessageHandler.ConnectionMessage.OVER.toString())
                                                        .toString());

And the client receives using:

JSONObject jsonObject = new JSONObject(dataInputStream.readUTF());

But, at this line above I get :

SEVERE: null
java.io.UTFDataFormatException: malformed input around byte 1
    at java.io.DataInputStream.readUTF(DataInputStream.java:656)
    at java.io.DataInputStream.readUTF(DataInputStream.java:564)
    at labrpc.secondquestion.Client.lambda$jButton3ActionPerformed$1(Client.java:499)
    at java.lang.Thread.run(Thread.java:748)

Somehow write corrupted the writeUTF or something like that (I've been searching for everything related to it and found nothing relevant), I've tried to remove the write from server just to test and these error doesn't appeared, but it's an important routine.

My question is : Does the write and writeUTF are mutually exclusive in socket communication?

Thanks in advance.

Ruan Kotovich
  • 579
  • 1
  • 4
  • 11
  • 2
    This can't possibly work. 1. The file could contain the byte 0, clashing with your end-of-file marker. 2. When reading the stream, there is no reason for the end-of-file marker to be the last byte in the buffer. You need to find a better protocol. For example, you could send the length of each message before sending the message. – JB Nizet Apr 07 '18 at 12:44
  • I've had to add the end of file marker as the consumer while on client side wasn't detecting the eof(the file was a .ZIP) – Ruan Kotovich Apr 07 '18 at 12:48
  • By sending the length of each message you mean sending the total file length? it's a really good idea, I'll try it when possible, thanks a lot ;) – Ruan Kotovich Apr 07 '18 at 14:59
  • I followed your guidelines and it works, thanks a lot friend ;) – Ruan Kotovich Apr 07 '18 at 17:19

1 Answers1

1

I solved it following a hint from JB Nizet

As I've already had the length of the file, I figured out that I could send the length to the client, so it could iterate only over the specified length, inferring the virtual end of file by the length and already read bytes.

Server Side: FileInputStream fileInputStream = new FileInputStream(threadItem.second);

 progressListener.dmaSend(threadItem.second.getName(), length);

 byte[] buffer = new byte[BLOCK_SIZE];

 for (int curLength, accumulator = 0; accumulator < length; outputStream.write(buffer, 0, curLength)) {
     System.out.println("Reading part [" + accumulator + "," + length + "]");
     accumulator += (curLength = fileInputStream.read(buffer));
     System.out.println("Sending part [" + accumulator + "," + length + "]");
 }

 System.out.println("File sent.");

Client Side:

 FileOutputStream fOutputStream = new FileOutputStream(new File("./received/" + obj.toString()));
 byte[] buffer = new byte[BLOCK_SIZE];

 for (int curLength, accumulator = 0; accumulator < length; fOutputStream.write(buffer, 0, curLength)) {
     System.out.println("Reading part [" + accumulator + "," + length + "]");
     accumulator += (curLength = dataInputStream.read(buffer));
     System.out.println("Sending part [" + accumulator + "," + length + "]");
 }

 fOutputStream.close();

So, it's been possible to write(the socket output)/read(the file input) on the server and write(the file output)/read(the socket input) on the client.

Ruan Kotovich
  • 579
  • 1
  • 4
  • 11