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

问题描述 投票:0回答:2

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

Socket.setSoTimeout()

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

java sockets stream
2个回答
55
投票

如果我只写入输出流上的套接字,它会阻塞吗?只有读取才能阻塞,对吧?

Socket
也可以块上写字1。操作系统只会缓冲一定量的未传输(或已传输但未确认)的数据。如果您写入内容的速度比远程应用程序读取它的速度快,则套接字最终将备份并且您的
write
调用将被阻塞。

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

操作系统内核无法提供无限量的内存来缓冲未发送或未确认的数据。阻止写入是解决这个问题的最简单方法。


回答这些后续问题:

那么有没有一种机制可以设置 超时吗?我不知道什么 它的行为......也许会被扔掉 如果缓冲区已满,则数据?或者可能 删除缓冲区中较旧的数据?

没有在 java.net.Socket 上设置写入超时的机制。有一个

Socket.setSoTimeout()
方法,但它影响
accept()
read()
调用...而不是
write()
调用。显然,如果您使用 NIO、非阻塞模式和选择器,您可以获得写入超时,但这并不像您想象的那么有用。

正确实现的 TCP 堆栈不会丢弃缓冲的数据,除非连接关闭。但是,当写入超时时,无法确定当前位于操作系统级缓冲区中的数据是否已被另一端接收到……。另一个问题是,您不知道最后一个

write
中有多少数据实际传输到操作系统级 TCP 堆栈缓冲区。由于缺乏用于重新同步流2的某些应用程序级协议,
write
超时后唯一安全的做法就是关闭连接。

相比之下,如果您使用数据报套接字(例如 UDP),则

write()
调用不会在相当长的 3 时间内阻塞。但缺点是,如果出现网络问题或远程应用程序无法跟上,消息将被丢弃,而不会通知任何一端。此外,您可能会发现消息有时会无序地传递到远程应用程序。这些问题将由您(开发人员)来处理。

1 - 但不是

DatagramSocket

2 - 理论上可以做到这一点,但对于大多数应用程序来说,在已经可靠的(在某种程度上)TCP/IP 流之上实现额外的重新同步机制是没有意义的。如果它确实有意义,您还需要处理连接关闭的可能性......因此“假设”它关闭会更简单。 3 - javadoc 并没有说 send
根本不会阻塞。但我希望操作系统会丢弃传出的数据报而不是阻塞。

    

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


8
投票
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4031100

© www.soinside.com 2019 - 2024. All rights reserved.