在 Java 中使用套接字时,如何在开始处理数据之前判断客户端是否已完成所有(二进制)数据的发送。例如考虑:
istream = new BufferedInputStream (socket.getInputStream());
ostream = new BufferedOutputStream(socket.getOutputStream());
byte[] buffer = new byte[BUFFER_SIZE];
int count;
while(istream.available() > 0 && (count = istream.read(buffer)) != -1)
{
// do something..
}
// assuming all input has been read
ostream.write(getResponse());
ostream.flush();
我读过类似的帖子,例如this https://stackoverflow.com/questions/534964/why-is-the-end-of-the-input-stream-never-reached-using-java-sockets,但找不到确凿的答案。虽然我的上述解决方案有效,但我的理解是,您永远无法真正判断客户端是否已完成发送所有数据。例如,如果客户端套接字发送了一些数据块,然后在发送更多数据之前阻塞等待来自另一个数据源的数据,则上面的代码很可能假设客户端已完成自 istream.available() 以来的所有数据发送将返回 0current字节流。
是的,你是对的 - 使用available()
这样是不可靠的。我个人很少使用available()
。如果您想读到最后stream(根据问题标题),继续打电话read()
直到返回-1。这就是最简单的一点。困难的一点是,如果您不希望流结束,而是希望“服务器当前想要向您发送的内容”结束。
正如其他人所说,如果您需要通过套接字进行对话,您must让协议解释数据在哪里结束。就我个人而言,我更喜欢“长度前缀”解决方案,而不是可能的“消息结束标记”解决方案 - 它通常使阅读代码变得更简单。然而,它可以使writing编码更加困难,因为您需要在发送任何内容之前计算出长度。如果您要发送大量数据,这会很痛苦。
当然,您可以混合和匹配解决方案 - 特别是,如果您的协议同时处理文本和二进制数据,我会strongly建议使用长度前缀字符串而不是以空结尾(或类似的内容)。如果您可以向解码器传递完整的字节数组并只返回一个字符串,那么解码字符串数据往往会容易得多 - 例如,您无需担心读取到字符的一半。您可以将其用作协议的一部分,但仍然具有整体“记录”(或您正在传输的任何内容)和“数据结束”记录,以便让阅读器处理数据并做出响应。
当然,如果您无法控制协议,那么所有这些协议设计内容都是没有意义的:(
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)