套接字中连接超时和读取超时有什么区别?

238

3个问题:

  1. 连接超时读取超时在套接字中有什么区别?

  2. 连接超时设置为“无限”意味着什么?在什么情况下会保持无限循环?什么可以触发无限循环的结束?

  3. 读取超时设置为“无限”意味着什么?在什么情况下会保持无限循环?什么可以触发无限循环的结束?

2个回答

296
  1. 套接字连接超时和读取超时有什么区别?

连接超时是在建立初始连接时的超时时间,即完成TCP连接握手。读取超时是等待读取数据的超时时间1。如果服务器(或网络)在客户端进行套接字read调用后<timeout>秒未传递任何数据,则会引发读取超时错误。

  1. 将连接超时设置为“无限大”意味着什么?在什么情况下可能会保持在一个无限循环中?什么可以触发无限循环结束?

这意味着连接尝试可能永远阻塞。没有无限循环,但可以通过另一个线程关闭套接字来取消阻塞连接尝试。(Thread.interrupt()调用也可能管用…不确定。)

  1. 将读取超时设置为“无限大”意味着什么?在什么情况下可能会保持在一个无限循环中?什么可以触发无限循环结束?

它意味着在套接字流上调用read可能会永远阻塞。再次强调,没有无限循环,但是read可以通过Thread.interrupt()调用、关闭套接字以及(当然)另一端发送数据或关闭连接来取消阻止。


1-它不是…正如一个评论者所认为的那样…套接字可以保持打开或空闲的超时时间。


11

这些是由JVM强制执行的TCP连接建立和等待读取套接字数据的超时值。

如果将值设置为无穷大,您将不会永远等待。这只是意味着JVM没有超时限制,操作系统将负责所有超时。但是,在某些缓慢的网络上,操作系统的超时时间可能非常长,我曾经看到过长达6分钟的超时时间。

即使为套接字设置了超时值,如果超时发生在本地代码中,则可能无法起作用。我们可以通过连接到被防火墙阻止或在交换机上拔掉电缆的主机来在Linux上重现此问题。

处理TCP超时的唯一安全方法是在不同的线程中运行连接代码,并在它花费的时间太长时中断该线程。


如果将值设置为无限大,您将不会永远等待。 只要不讨论“无限大”的含义,就肯定会发生您等待很长时间的情况。我们曾经遇到过这样一个案例,HttpURLConnection.getResponseCode()在大约一周的时间里一直挂起,直到我们重新启动了进程。显然在JVM端没有设置超时,Linux操作系统端也没有设置超时。 - Tom Fink
最后一段不正确。连接最多会在一分钟后超时。单独的线程是完全不必要的。如果没有数据,你肯定可以有永远运行的读取。然而,Javadoc关于默认连接超时无限的说法是错误的。它并不是无限的。 - user207421
1
@comeGetSome 这不正确。你可以关闭输入的套接字。这将导致被阻塞的读取遇到流的末尾。 - user207421
@comeGetSome:我不得不使用一个线程来持有一个打开的HTTP URL连接的引用来实现这个。当该线程关闭连接时,另一个线程会抛出“java.net.SocketException: Socket closed”。感谢JDK-8075484的bug让我这么做! - fmcato
@comeGetSome,你肯定可以调用Socket.shutdownInput()而不需要手把手地指导吧?注意:这些超时是由TCP而不是JVM强制执行的。 - user207421
@EJP,你是对的,它甚至可以在Socket.close()上工作;然而,在这种情况下,读/写操作不会遇到EOF,而是抛出一个IO异常。 - comeGetSome

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接