我现在正在服务器上为游戏工作。服务器的数据包读取循环是阻塞的,并且通常等待直到接收到数据包以继续循环。但是,如果客户端断开连接,DataInputStream将返回单个字节(-1),并且如预期的那样快速连续执行循环。但是,我没有使用DataInputStream的read()方法一次读取一个字节,我使用read(byte [])方法将它们一次性读取到一个字节数组中。因此,我无法轻易检测到流是否返回值为-1的单个字节。
可能的解决方案:我可以检查数组的第一个字节是否为-1,如果是,则循环遍历数组以查看数组的其余部分是否为零。这样做看起来效率极低,而且我觉得随着客户端数量的增加会影响性能。
这是我的数据包读取循环的简化版本:
while (!thread.isInterrupted() && !isDisconnected())
{
try
{
byte[] data = new byte[26];
data = new byte[26];
input.read(data);
//Need to check if end of stream here somehow
Packet rawPacket = Packet.extractPacketFromData(data); //Constructs packet from the received data
if(rawPacket instanceof SomePacket)
{
//Do stuff with packet
}
}
catch(IOException e)
{
disconnectClient(); //Toggles flag showing client has disconnected
}
}
答案 0 :(得分:5)
您对read(byte[])
的理解不正确。它不会将数组中的值设置为-1
。
Javadoc说:
<强>返回:强> 读入缓冲区的总字节数,如果由于已到达流末尾而没有其他数据,则为
-1
。
您需要检查返回值:
int bytesRead = input.read(data);
if (bytesRead == -1)
{
// it's end of stream
}
作为旁注,即使只是正常读取数据,也需要检查读取的字节数是否是您请求的字节数。对read
的调用无法保证实际填充您的数组。
您应该查看完全阅读的readFully()
,并为流的结尾抛出EOFException
:
从输入流中读取一些字节并将它们存储到缓冲区数组b中。读取的字节数等于b的长度。 此方法将阻塞,直到出现以下某种情况:
b.length
个字节的输入数据可用,在这种情况下可以正常返回。- 检测到文件结尾,在这种情况下会抛出
EOFException
。- 发生I / O错误,在这种情况下会抛出
IOException
以外的EOFException
。