java套接字/输出流写入:它们阻塞吗?

Posted

技术标签:

【中文标题】java套接字/输出流写入:它们阻塞吗?【英文标题】:java socket / output stream writes : do they block? 【发布时间】:2010-11-23 06:12:01 【问题描述】:

如果我只是在输出流上写入套接字,它会阻塞吗?只有读取可以阻塞,对吗?有人告诉我写可以阻塞,但我只看到套接字读取方法的超时功能 - Socket.setSoTimeout()

对我来说,写可能会阻塞是没有意义的。

【问题讨论】:

没有超时功能这一事实本身并不表示它不会阻塞。它确实存在的一个迹象是缺少返回值:如果它没有阻塞,为什么它不返回实际写入的字节数?只需尝试一下即可给出另一个指示。 【参考方案1】:

对 Socket 的写入也可能会阻塞,尤其是在它是 TCP Socket 的情况下。操作系统只会缓冲一定数量的未传输(或传输但未确认)的数据。如果你写东西的速度快于远程应用程序的读取速度,套接字最终会备份,你的 write 调用将阻塞。

回答这些后续问题:

那么有没有一种机制来设置 为此超时?我不确定是什么 它的行为......也许会扔掉 缓冲区已满时的数据?或者可能 删除缓冲区中的旧数据?

没有在 java.net.Socket 上设置写入超时的机制。有一个Socket.setSoTimeout() 方法,但它影响accept()read() 调用......而不是write() 调用。显然,如果您使用 NIO、非阻塞模式和 Selector,您可以获得写入超时,但这并不像您想象的那么有用。

除非连接关闭,否则正确实现的 TCP 堆栈不会丢弃缓冲的数据。但是,当您收到写入超时时,不确定当前位于操作系统级缓冲区中的数据是否已被另一端接收......另一个问题是您不知道上一个write 中的数据有多少实际传输到了操作系统级别的TCP 堆栈缓冲区。由于缺少一些用于重新同步流的应用程序级协议*,在write 超时后唯一安全的做法是关闭连接。

相比之下,如果您使用 UDP 套接字,write() 调用不会阻塞很长时间。但不利的一面是,如果出现网络问题或远程应用程序跟不上,消息将被丢弃在地板上,而不会通知任何一方。此外,您可能会发现消息有时会乱序传递到远程应用程序。由您(开发者)来处理这些问题。

* 理论上可以做到这一点,但是对于大多数应用程序来说,在已经可靠(到一定程度)的 TCP/IP 流之上实现额外的重新同步机制是没有意义的。如果它确实有意义,您还需要处理连接关闭的可能性......所以假设它关闭会更简单。

【讨论】:

【参考方案2】:

这样做的唯一方法是使用 NIO 和选择器。

请参阅此错误报告中来自 Sun/Oracle 工程师的文章: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4031100

【讨论】:

以上是关于java套接字/输出流写入:它们阻塞吗?的主要内容,如果未能解决你的问题,请参考以下文章

将 Spark 流输出写入套接字

Java实现文件写入——IO流(输入输出流详解)

java.IO输入输出流:过滤流:buffer流和data流

11Java IO NIO

java之九 基本输入输出流

Java 输入/输出——理解Java的IO流