java socket / output stream写道:它们阻塞了吗?

时间:2009-08-27 04:44:16

标签: java sockets stream

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

对我来说,写入可以阻止它是没有意义的。

2 个答案:

答案 0 :(得分:48)

Socket上的写操作也可以阻塞,特别是如果它是TCP Socket。操作系统仅缓冲一定量的未传输(或传输但未确认)数据。如果您编写的内容比远程应用程序能够读取的速度快,那么套接字最终会备份,并且您的write调用将会阻止。

回应这些后续问题:

  

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

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

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

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

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

答案 1 :(得分:7)

执行此操作的唯一方法是使用NIO和选择器。

在此错误报告中查看Sun / Oracle工程师的文章: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4031100