如果我只是在输出流上写入套接字,它会阻塞吗?只有读取可以阻止,对吧?有人告诉我写入可以阻止,但我只看到套接字读取方法的超时功能 - Socket.setSoTimeout()
。
对我来说,写入可以阻止它是没有意义的。
答案 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