views:

324

answers:

3

I have a Java Client which sends UTF-8 strings to a C# TCP-Server, I'm using a DataOutputStream to send the strings. The code looks like this:

public void sendUTF8String(String ar) {
 if (socket.isConnected()) {
  try {
   dataOutputStream.write(ar.getBytes(Charset.forName("UTF-8")));
   dataOutputStream.flush();
  } catch (IOException e) {
   handleException(e);
  }
 }
}

The problem is that flush doesn't seem to work right. If I send two Strings close to each other, the server receives only one message with both strings. The whole thing works if I do a Thread.sleep(1000) between calls, this is obviously not a solution. What am I missing?

+6  A: 

flush() doesn't guarantee that a data packet gets shipped off. Your TCP/IP stack is free to bundle your data for maximum efficiency. Worse, there are probably a bunch of other TCP/IP stacks between you and your destination, and they are free to do the same.

I think you shouldn't rely on packet bundling. Insert a logical terminator/divider in your data and you will be on the safe side.

Carl Smotricz
I was starting a response too but it only added that the buffering on the receive side could mess up any flushing you could do on the client even if you could reliably flush (which in general you can). But no matter what you do on the client, the server will still be buffering its socket data.
PSpeed
+2  A: 

You shouldn't worry about how the data is broken up into packets.

You should include the length of the string in your messages, and then on the receiving end you would read the length first. So for example to send you would do

byte[] arbytes = ar.getBytes(Charset.forName("UTF-8"));
output.writeInt(arbytes.length)
output.write(arbytes)

and then in your reader you do

byte[] arbytes = new byte[input.readInt()];
for(int i = 0; i < len; i++){
     arbytes[i] = input.read();
}
//convert bytes back to string.

You can't just call input.read(arbytes) because the read function doesn't necessarily read the entire length of the array. You can do a loop where you read a chunk at a time but the code for that is a bit more complex.

Anyway, you get the idea.


Also, if you really want to control what goes in what packets, you can use Datagram Sockets, but if you do that then delivery of the packet is not guaranteed.

Chad Okere
A: 

Socket send a stream of data, not messages. You shouldn't rely on the packets you receive being the same size as they are sent. Packets can be grouped together as you have seen but they can also be broken up. Use @Chad Okere's suggestion on how to ensure you get blocks the same was they are sent.

However in your case, you can just use

dataOutputStream.writeUTF(ar); // sends a string as UTF-8

and

String text = dataInputStream.readUTF(); // reads a string as UTF-8
Peter Lawrey