如果我只写入输出流上的套接字,是否会阻塞?只有读取可以阻止,对吧?有人告诉我写入可以阻止,但我只能看到套接字的读取方法的超时功能 - Socket.setSoTimeout()
。Java插座/输出流写道:他们阻止?
写入可能会阻止我没有意义。
如果我只写入输出流上的套接字,是否会阻塞?只有读取可以阻止,对吧?有人告诉我写入可以阻止,但我只能看到套接字的读取方法的超时功能 - Socket.setSoTimeout()
。Java插座/输出流写道:他们阻止?
写入可能会阻止我没有意义。
对Socket的写入操作也会阻塞,特别是如果它是TCP Socket。操作系统只会缓冲一定数量的未发送(或已发送但未确认)的数据。如果你写东西的速度比远程应用程序能够读取的速度快,那么套接字将最终备份,并且你的呼叫将被阻止。
应对这些后续问题:
那么,有没有一种机制来设置 超时呢?我不知道它会有什么 的行为......如果缓冲区已满,可能会丢掉 数据?或者可能 删除缓冲区中较旧的数据?
没有机制在java.net.Socket上设置写入超时。有一个Socket.setSoTimeout()
方法,但它影响accept()
和read()
调用...而不是write()
调用。显然,如果你使用NIO,非阻塞模式和Selector,你可以得到写超时,但这并不像你想象的那样有用。
正确实施的TCP堆栈不会丢弃缓存的数据,除非连接关闭。但是,当您获得写入超时时,目前在OS级缓冲区中的数据是否已由另一端接收或不确定。另一个问题是,您不知道最近的write
中的多少数据实际传输到OS级别的TCP堆栈缓冲区。如果缺少一些应用级协议来重新同步流*,在write
上超时后唯一安全的做法是关闭连接。
相比之下,如果您使用UDP套接字,write()
调用将不会阻塞任何相当长的时间。但缺点是,如果出现网络问题或远程应用程序无法跟上,消息将丢在地板上,而不会通知任何一端。另外,您可能会发现邮件有时会不按顺序发送到远程应用程序。这将取决于您(开发人员)处理这些问题。
*理论上可以做到这一点,但对于大多数应用程序来说,在已经可靠(到点)的TCP/IP流之上实现额外的重新同步机制是没有意义的。如果确实有意义,那么您还需要处理连接关闭的可能性......所以假设它关闭会更简单。
要做到这一点的唯一方法是使用NIO和选择器。
参见从Sun/Oracle的工程师书面记录这个bug报告: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4031100
,有没有超时功能,这一事实本身不是表明它不会阻止。它所做的一个迹象是没有返回值:如果不阻塞,为什么它不返回实际写入的字节数?另一个迹象是只是尝试它。 – EJP 2015-04-17 23:01:45