在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();
我对SO如阅读类似的帖子这个,也没有找到确凿的答案.虽然上面的解决方案有效,但我的理解是,您永远无法确定客户端是否已完成发送所有数据.例如,如果客户端套接字发送了一些数据块然后阻止等待来自另一个数据源的数据,然后它可以发送更多数据,那么上面的代码可能很好地假设客户端已完成发送所有数据,因为istream.available()将为当前字节流返回0 .
是的,你是对的 - available()
像这样使用是不可靠的.我个人很少使用available()
.如果你想要读到直到你到达流的末尾(根据问题标题),继续调用read()
直到它返回-1.这很容易.如果你不想要流的结束,那么硬盘就是"服务器此刻想要发送给你的内容"的结尾.
正如其他人所说,如果你需要通过套接字进行对话,你必须让协议解释数据完成的位置.就个人而言,我更喜欢"消息令牌结束"解决方案的"长度前缀"解决方案 - 它通常可以使阅读代码更简单.但是,它可以使编写代码更难,因为您需要在发送任何内容之前计算出长度.如果您可以发送大量数据,这会很痛苦.
当然,你可以混合和匹配解决方案 - 特别是,如果你的协议处理文本和二进制数据,我强烈建议长度前缀字符串而不是空终止它们(或类似的东西).如果您可以将解码器传递给一个完整的字节数组并只返回一个字符串,那么解码字符串数据往往会容易得多 - 例如,您不必担心读取字符的一半.您可以将此作为协议的一部分使用,但仍然具有"数据结束"记录的整体"记录"(或任何您正在传输的记录),以便让读者处理数据并做出响应.
当然,如果你不能控制协议,所有这些协议设计的东西都没有实际意义:(
我认为这是一个更多的协议任务,假设你是编写应用程序的发送方和接收方的人.例如,您可以实现一些简单的逻辑协议,并将数据分成数据包.然后将数据包分成两部分:头部和身体.然后说你的头由一个预定义的起始序列组成,并包含正文中的字节数.忘记在bofy中作为数据包的第一个字节启动序列和简单传输字节数.那你就可以解决你的问题.