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套接字/输出流写入:它们阻塞吗?的主要内容,如果未能解决你的问题,请参考以下文章