Java TCP:从网络读取输入流时缓冲区下溢

问题描述

我在解析缓冲区时遇到来自 Java 中 TCP 套接字的 InputStream 的问题:

InputStream stream = (InputStream)socket.getInputStream();
int numBytesReceived = 0;
byte[] receiveBuffer = new byte[20];
while(numBytesReceived != -1) {
    
    numBytesReceived = 0;
    numBytesReceived = stream.read(tempReceive);

    // Code to start reading bytes from the receiveBuffer and parse into messages here
}

假设我们从缓冲区解析的每条消息都包含一个标头字节,指示消息中数据的大小(以字节为单位),其余为数据字节。

从上面的代码来看,receiveBuffer 被分配了 20 字节。下面是一个例子: [2,1,3,4,0]

在这个例子中,我们有 3 条消息(我将每个标题字节加粗):

  • 一条消息的头部为 2,有 2 个数据字节 [2,1]
  • 第二条消息包含 3 个标头,因此 3 个数据字节 [3,1]
  • 第三条消息包含 4 个标头,因此 4 个数据字节 [4,1]

缓冲区的其余部分只是 0。这很好,直到用户开始发送大量数据包,因此 receiveBuffer 可能如下所示:

[2,2,2]

本例中有6条消息,但第6条消息被截断。我的代码将尝试读取 2 个不存在的字节,并抛出 BufferUnderflowException

我该怎么做才能确保在每个 read() 上一次读取我发送的所有消息?我不知道为什么它会切断消息。

如果我找到一种一次性获取所有字节的方法,那么它并不能真正避免用户一次发送数百到数千条消息,我将拥有一个非常大的缓冲区,因此我需要保留缓冲区大小受限(假设我每条消息最多发送 20 个字节)

解决方法

如果消息被截断(如果我们没有读完消息的所有字节),我已经设法通过在下一次循环迭代中继续 read() 来解决这个问题。

如果一条消息如示例中所示被截断,它会继续到下一个 read() 并且我只需要在解析它之前检查我之前是否正在阅读一条消息。