套接字上的 InputStream 读取零

InputStream on socket reads zeros

我尝试在服务器端接收原始二进制数据包。我可以控制数据格式并指定数据包的前 4 个字节来描述数据包的长度(它是一个转换为 byte[] 并返回的 int 值)。这非常有效,我得到了正确的数字(我也可以监控和检查客户端)。这是代码:

is = connectionSocket.getInputStream();
byte[] intArray = new byte[4];
//read the 4-byte int value to array
is.read(intArray, 0, 4);
int packetLength = ByteBuffer.wrap(intArray).getInt();

然后我想将包(不包括 length-header)读取到 custom-fit 字节数组:

byte[] packet = new byte[packetLength];//make a buffer ready
is.read(packet, 0, packetLength);//read the whole packet to array

如果发送的byte[]长度为1444或更小,一切正常。但超出此限制的数据包将无法正常接收。 packet-array开头会正确填充数据,但是limit之后,到最后只有零,像这样

Positon: ...|1440|1441|1442|1443|1444|1445|1446|1447|.........|packetLength-1
Data:    ...| 59 |-73 | 125| -3 |  0 |  0 |  0 |  0 |..zeros..| 0

从我 13 岁开始,years-old-wannabe-internet-tuning-master 我仍然记得,Windows 机器上有一个大约 1500 字节的标准 MTU(最大传输单元)。事实上,我的接收网络适配器的 MTU 为 1500。这令人怀疑地接近 1444,所以我增加了 MTU,但遗憾的是没有结果。 Java 不应该用 low-level 之类的东西来打扰我,但这也许不是巧合。顺便说一句,客户端是 Android 智能手机,接收器是 Windows 7 机器。

是否有人有其他想法或更好的解决方案?

您忽略了 read(), 返回的计数并假设它已填满缓冲区。它没有义务这样做。请参阅 Javadoc。

正确执行您正在做的事情的简单方法是使用 DataInputStream.readInt(),,然后使用 readFully().

NB 当然,与您的评论相反,仅添加 int size = 根本没有效果。这是不可能的。由于某些其他原因,时间发生了变化,因此四个字节真正到达了。

我终于发现了 read 的类竞争条件性质,但感谢您的帮助和澄清。当我观察到设置调试停止解决了问题时,我注意到了这一点,这让缓冲区有时间完成它们的工作。使用 DataInputStream 也更易于编写代码,再次感谢。这是我(希望如此)的最终解决方案:

DataInputStream dis = new DataInputStream(connectionSocket.getInputStream());
int packetLength = dis.readInt();
byte[] packet = new byte[packetLength];//make a buffer ready       
dis.readFully(packet);//read full packet to buffer