Reputation: 1469
I have a TCP socket client-server program in Java.
From the client, I send several times per sencond a binary message (binary data from a byte[]).
From the server, I want to read those messages in the same order and size.
The problem is that the server apparently dont always read the messages in the same size. It seems to "group" them. For example:
The client sends: 12 bytes - 12 bytes - 12 bytes - 12 bytes - 15 bytes - 15 bytes
The server receives: 12 bytes - 48 bytes - 15 bytes - 15 bytes
How can I prevent this?
Right now, my code is:
Client:
(initialization)
mySocket = new Socket(direccion, puerto);
mySocket.setTcpNoDelay(true);
BufferedOutputStream os = new BufferedOutputStream( mySocket.getOutputStream() );
(sending)
os.write( bytes );
os.flush();
Server
(initialization)
serverSocket = new ServerSocket(12321);
Socket con = serverSocket.accept();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
(receiving)
char[] msg = new char[1024];
String mensaje;
int nbytes;
nbytes = reader.read(msg);
I cant manually separate messages that come grouped, because they are binary messages, and this module cant "understand" them.
So, the question is: How can I assure that the reader gets the messages individually?
Thanx.
Upvotes: 0
Views: 1797
Reputation: 20059
You are using a Stream of data to transport your messages. A stream is conceptionally just a sequence of bytes - there are no messages. You need to take care of splitting the stream into messages/packets yourself. You could even receive part of a message with one read-call and the next part with the next call in your current code. As it is now your code is fundamentally flawed.
Introduce a mechanism that allows clear detection where a message starts/ends. A simple approach would be to just encode the length of each packet into the first byte(s) of each packet. The receiver can then read the length first and after that it knows how many of the following bytes belong to that packet.
Another approach is to have a message separator symbol that signals the end of the current packet. Since you are sending binary data, this would require that the packets not contain all possible byte values or you need encode the packet in a way that it doesn't use every possible byte value.
The approach with the length is much simpler to implement, while the end symbol approach would be useful for schemes where you easily can introduce a new symbol (e.g. if the entire packet were huffman encoded).
Upvotes: 2
Reputation: 91017
It is the nature of TCP connections that they transport a stream.
Your options are
separate the messages manually, e.g. by prepending a length field in front of every message. This requires changing the protocol.
use a protocol different than TCP. Either UDP (but then you lose reliability) or STCP (where I am not sure that Java is capable of this).
Upvotes: 1