简体   繁体   中英

How to receive the same messages sent via TCP socket?

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.

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 (eg if the entire packet were huffman encoded).

It is the nature of TCP connections that they transport a stream.

Your options are

  1. separate the messages manually, eg by prepending a length field in front of every message. This requires changing the protocol.

  2. 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM