Java: Socket Loss

We are developing a server application in Java (1.6), which is a transactional server that listens for connections through TCP sockets. Each new connection creates a new thread, which is maintained until the connection is closed. Each client sends transactions to the server to be processed, and then the response is sent back to the client.

It works great. The problem arises when we want to send many asynchronous transactions (or messages) through the same socket. I wrote a small application that sends 1000 transactions with an interval of 10 ms between each transaction. The application is asynchronous, so messages are sent and responses are in the middle.

This is the code from the part that processes incoming messages and sends them to another processed component (this component has a thread pool):

public void run() { ... ... socketBuf = new BufferedInputStream(input); baos = new ByteArrayOutputStream(); while ((bytes_read = socketBuf.read(buffer)) != -1) { if (bytes_read < 0) { log.error("Tried to read from socket, read() returned < 0, Closing socket."); return; } baos.write(buffer, 0, bytes_read); break; } if (bytes_read >= 0) { baos.flush(); byte data[] = baos.toByteArray(); if (data.length > 0) { GWTranData tData = posMessage.decode(data, false); if (tData.getMessageType() > 0) { // Send to the Pre-Online Manager to be processed PreOnlineJob newJob = new PreOnlineJob(tData); newJob.addJobStatusListener(this); GWServer.getPreOnlineInstance().addJob(newJob); } } } else { clientSocket.close(); break; } } while(true); } 

The problem that we encountered when sending many transactions in a short time is that some messages are lost and do not reach the server. Through in-depth analysis, we found that when messages are sent too fast, there are more than one message in the buffer, so the data [] has two or more messages, but only one will be executed. The size of the sent message is 200 bytes, so the 512 buffer is larger than enough.

Are there any problems with how I implemented the socket? Is there a better way?

Thanks guys.

+4
source share
2 answers

The problem is how you consume bytes read from the socket. Your assumption is that you get one “message” per read. This assumption is incorrect: TCP does not know the boundaries of your application messages, but gives you a stream of bytes, so you can receive several messages at once, or part of a message, or both.

You need to buffer the raw part of the received stream, check to see if you have received the full message, read a little more until you do this, process the message and continue in the loop.

Change 0:

There are several ways to develop your application layer protocol over TCP:

  • fixed-length messages (easy),
  • (an explicit sequence of bytes is required to indicate the end / beginning of a message, for example, SOH in FIX or \r\n in HTTP),
  • posts with a long prefix that @Thomas offers in the comments,
  • "self-describing" messages - like s-expressions or what not, you need to parse,
  • possibly others.
+6
source

You need to configure the code to process messages as they arrive. Currently, you are accumulating the entire stream from connecting to EOS into one giant byte array, and then processing it as if it contains only one message. This is not only wrong from the point of view of “losing” messages (it is you who are losing), but it is also very wasteful for time and space. You do not need to wait for EOS before you can process the first message. You need to figure out how to read the stream until you have exactly one message, process it, and then repeat to figure out the next message ending in EOS.

+1
source

All Articles