2009-08-27 36 views
31

如果我只写入输出流上的套接字,是否会阻塞?只有读取可以阻止,对吧?有人告诉我写入可以阻止,但我只能看到套接字的读取方法的超时功能 - Socket.setSoTimeout()Java插座/输出流写道:他们阻止?

写入可能会阻止我没有意义。

+0

,有没有超时功能,这一事实本身不是表明它不会阻止。它所做的一个迹象是没有返回值:如果不阻塞,为什么它不返回实际写入的字节数?另一个迹象是只是尝试它。 – EJP 2015-04-17 23:01:45

回答

45

对Socket的写入操作也会阻塞,特别是如果它是TCP Socket。操作系统只会缓冲一定数量的未发送(或已发送但未确认)的数据。如果你写东西的速度比远程应用程序能够读取的速度快,那么套接字将最终备份,并且你的呼叫将被阻止。

应对这些后续问题:

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

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

正确实施的TCP堆栈不会丢弃缓存的数据,除非连接关闭。但是,当您获得写入超时时,目前在OS级缓冲区中的数据是否已由另一端接收或不确定。另一个问题是,您不知道最近的write中的多少数据实际传输到OS级别的TCP堆栈缓冲区。如果缺少一些应用级协议来重新同步流*,在write上超时后唯一安全的做法是关闭连接。

相比之下,如果您使用UDP套接字,write()调用将不会阻塞任何相当长的时间。但缺点是,如果出现网络问题或远程应用程序无法跟上,消息将丢在地板上,而不会通知任何一端。另外,您可能会发现邮件有时会不按顺序发送到远程应用程序。这将取决于您(开发人员)处理这些问题。

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

+0

那么有没有一种机制来为此设置超时?我不确定它会有什么行为......如果缓冲区已满,可能会丢弃数据?或者可能删除缓冲区中的旧数据? – jbu 2009-08-27 05:20:07

+0

有没有办法重现这个测试?我想让我的应用程序能够从此恢复。为此我需要测试 – Zamir 2015-02-18 10:28:20

+0

AFAIK,没有一般的方法。但取决于应用程序的性质(例如,它在与什么对话),有很多方法。问一个新的问题...并具体。 – 2015-02-18 22:27:00