Java:socket消息丢失了

Rob*_*ert 4 java sockets

我们正在开发一个Java(1.6)服务器应用程序,它是一个事务服务器,通过TCP套接字监听连接.每个新连接都会创建一个新线程,该线程将保持活动状态,直到连接关闭 每个客户端都会将事务发送到将要处理的服务器,然后将响应发送回客户端.

这很好用.当我们想要通过同一个套接字发送许多异步事务(或消息)时,就会出现问题.我写了一个小应用程序,在每次事务之间发送1000个事务,间隔为10毫秒.该应用程序是异步的,因此发送消息并且响应位于中间.

这是处理incomming消息并将它们发送到另一个要处理的组件的部分的代码(该组件有一个线程池):

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);
  } 
Run Code Online (Sandbox Code Playgroud)

在短时间内发送许多事务时我们遇到的问题是某些消息丢失而无法到达服务器.进行深入分析,我们发现当消息发送得太快时,缓冲区中有多条消息,因此data []有两条或更多条消息,但只会执行一条消息.发送的消息大小为200字节,因此512的缓冲区已足够.

我实现套接字读取的方式有什么问题吗?有没有更好的办法?

多谢你们.

Nik*_*sov 6

问题在于消耗从套接字读取的字节的方式.您的假设是每次阅读都会收到一条"消息".这个假设是错误的 - TCP不知道你的应用程序消息边界,但是给你一个字节,所以你可以一次得到几条消息,或者一部分消息,或者两者兼而有之.

您必须缓冲接收到的流的未处理部分,检查是否有完整的消息,阅读更多信息,处理消息,然后继续循环.

编辑0:

有几种方法可以在TCP上设计应用程序级协议:

  • 固定长度的消息(简单),
  • 分隔消息(需要显式字节序列来指定消息的结束/开始,如SOHFIX或\r\nHTTP中),
  • @Thomas在评论中建议的长度加前缀的消息
  • "自描述"消息 - 比如s表达式或者不需要解析的表达式,
  • 也许其他人.