java - 使用套接字时 'end of stream' 是什么意思

标签 java sockets network-programming

在 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 上读过类似的帖子,例如 this ,但找不到确凿的答案。虽然我上面的解决方案有效,但我的理解是,您永远无法真正判断客户端是否已完成所有数据的发送。例如,如果客户端套接字发送了几 block 数据,然后在它可以发送更多数据之前阻塞等待来自另一个数据源的数据,上面的代码很可能假设客户端已经完成了自 istream.available() 以来的所有数据的发送将为 当前 字节流返回 0。

最佳答案

是的,你是对的 - 像这样使用 available() 是不可靠的。我个人很少使用available()。如果您想阅读直到到达 stream 的末尾(根据问题标题),请继续调用 read() 直到它返回 -1。这很容易。困难的一点是,如果您不想要流的结尾,而是“服务器此刻想要发送给您的内容”的结尾。

正如其他人所说,如果您需要通过套接字进行对话,您必须让协议(protocol)解释数据在哪里结束。就我个人而言,在可能的情况下,我更喜欢“长度前缀”解决方案而不是“消息结束 token ”解决方案——它通常使阅读代码更简单。但是,它会使编写代码变得更加困难,因为您需要在发送任何内容之前计算出长度。如果您可以发送大量数据,这会很痛苦。

当然,您可以混合和匹配解决方案 - 特别是,如果您的协议(protocol)同时处理文本和二进制数据,我会强烈推荐使用长度前缀字符串而不是以空值结尾的字符串(或任何类似的东西)。如果您可以向解码器传递一个完整的字节数组并返回一个字符串,那么解码字符串数据往往会容易得多 - 例如,您不必担心读取到一半的字符。您可以将其用作协议(protocol)的一部分,但仍然具有带有“数据结束”记录的整体“记录”(或您正在传输的任何内容),以让阅读器处理数据并做出响应。

当然,如果您无法控制协议(protocol),那么所有这些协议(protocol)设计的东西都是没有意义的:(

关于java - 使用套接字时 'end of stream' 是什么意思,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/649320/

相关文章:

java - 如何从不同的 jar 中订购 spring @PostConstruct 调用?

linux - 监听端口上的选择性多播组

networking - SDN中的管理平面是什么?

c - 如何在C HTTP客户端程序中向文件写入HTTP请求

java - 如何在 Java 中处理和解析包含混合内容的文本文件

java - Oracle 存储过程自动化

c++ - 使用 winsock 设置主机名?

java - 客户端可以同时向多个服务器发送消息吗?

java - 如何获知网络状态变化?

java - 如何使用 Servlet 从服务器下载文件