【问题标题】:Java Socket - how does the read() method know if the end of stream has been reached? [duplicate]Java Socket - read() 方法如何知道是否已到达流的末尾? [复制]
【发布时间】:2015-08-23 02:46:24
【问题描述】:
  1. InputStream.read(byte[]) 方法如何知道是否已到达“流结束”并返回“-1”?

  2. 返回“-1”的全部条件是什么?

  3. 如何检测“流结束”(不发送包含之前要读取的总字节数的整数)?

使用示例:

InputStream input = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
for(int size = -1; (size = input.read(buffer)) != -1; ) {
    baos.write(buffer, 0, size);
}

【问题讨论】:

  • 如果是TCP socket,因为对方已经发送TCP握手消息关闭连接。
  • 如果它不是 TCP 套接字,它根本不会传递 -1,因为 Java 支持的唯一其他套接字是 UDP,它不是流协议,也没有流的结束。
  • @Nayuki 为什么要删除tcp 标签?这就是问题的意义所在。

标签: java sockets tcp inputstream


【解决方案1】:

InputStream 是一种具有许多实现的抽象类型。例如,FileInputStream 将在您到达文件末尾时返回 -1。如果它是 TCP 套接字,如果连接已关闭,它将返回 -1。如何确定流结束取决于实现。

【讨论】:

  • 从题主看,我觉得这里比较感兴趣的是socket实现。
【解决方案2】:

没有。

当您尝试从套接字读取 n 个字节时,调用可能会在 n 个字节准备好之前返回,并返回读取的字节数。 read() 如何决定返回?基于超时。超时值在 AbstractPlainSocketImpl.java 中注释为 SO_TIMEOUT。实际上,真正的读取发生在本机代码中,可能是用 C 编写的,SO_TIMEOUT 默认为本机代码所具有的任何内容。但是,您可以使用 Socket.setSocketTimeout(millis) 设置超时值。

SocketInputStream.java

        n = socketRead(fd, b, off, length, timeout);
        if (n > 0) {
            return n;
        }

如果您遵守 HTTP 协议,客户端和服务器会使用 content-length 标头进行协调,以相互指示请求和响应何时结束,以及新请求和响应何时开始。接收到的字节顺序由 TCP 层处理。

套接字流没有流结束检查,如文件的 feof 检查。它是一种双向通信读写。但是,您可以检查字节是否可供读取。在客户端或服务器选择关闭之前,TCP 连接一直处于活动状态。

【讨论】:

  • 确实如此。当对等方关闭连接时,TCP 套接字传递流结束。您的第一段和最后一段与此相矛盾。
  • ... 并且文件没有 EOF 标记。如果已经接收到数据或流的结尾,read() 不会根据超时决定何时返回。这个答案读起来只是猜测。
  • SocketInputStream.java --> int read(byte b[], int off, int length, int timeout) 抛出 IOException --> n = socketRead0(fd, b, off, length, timeout); SocketInputStream .java --> private native int socketRead0(FileDescriptor fd, byte b[], int off, int len, int timeout) throws IOException; SocketInputStream.c --> nread = recv(fd, bufP, len, 0); man7.org/linux/man-pages/man2/recv.2.html gnu.org/software/libc/manual/html_node/EOF-and-Errors.html
  • 我进一步研究了 EOF 是如何决定的。文件指针通过标志跟踪 EOF。 struct_FILE.h --> #define _IO_EOF_SEEN 0x0010 struct_FILE.h --> #define __feof_unlocked_body(_fp) (((_fp)->_flags & _IO_EOF_SEEN) != 0) fileops.c _IO_file_xsgetn --> count = _IO_SYSREAD (fp, s, count); if (count == 0) fp->_flags |= _IO_EOF_SEEN; 来自这一点真的很乱,宏,vtables等......。 总结,_IO_SYSREAD 返回 -1 表示 EOF。 libioP.h --> #define _IO_SYSREAD(FP, DATA, LEN) JUMP2 (__read, FP, DATA, LEN)
  • 我不知道你的第一条评论应该证明什么。它没有。将难以辨认的代码放入 cmets 并不是什么好事。修正你的答案。错了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 1970-01-01
相关资源
最近更新 更多