如何避免NoRouteToHostException?

Gru*_*eck 59 java sockets networking exception-handling

披露:我正在处理的代码是大学课程.

背景:我要完成的任务是报告不同线程技术的效果.为此,我编写了几个类来响应客户端使用Java套接字的请求.我们的想法是向服务器发送请求并报告不同的线程策略如何处理这个问题.每个客户端将发出100个请求,并且在每次迭代中,我们将客户端数量增加50,直到出现故障.

问题:可重复且一致地发生异常:

Caused by: java.net.NoRouteToHostException: Cannot assign requested address
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)

这种情况发生在几种情况下,包括客户端和服务器都在localhost上运行时.可以成功连接一段时间,尝试连接150个客户端后不久就会抛出异常.

我的第一个想法是它可能是Linux对打开文件描述符(1024)的限制,但我不这么认为.我还检查了套接字之间的任何和所有连接是否正确关闭(即在正确的finally块内).

我对发布代码犹豫不决,因为我不确定哪些部分最相关,并且不希望在问题中有大量代码.

有没有人遇到过这个?如何避免NoRouteToHostException?


编辑(进一步的问题是斜体)

到目前为止,一些好的答案指向短暂的端口范围或RFC 2780.这两个都表明我有太多的连接打开.对于两者而言,似乎需要达到此限制的连接数表明在某些时候我没有关闭连接.

调试了客户端和服务器后,两者都被观察到了方法调用myJava-Net-SocketInstance.close().这表明连接正在关闭(至少在非例外情​​况下).这是正确的建议吗?

此外,是否还需要等待操作系统级别才能再次使用端口?如果在运行下一次尝试之前只需要短时间(或乐观地运行命令),则可以为每个50多个客户端单独运行程序.


编辑v2.0

在提供了良好的答案后,我修改了我的代码,使用方法setReuseAddress(true)与客户端上的每个Socket连接.这没有达到预期的效果,我仍然限制在250-300个客户端.程序终止后,运行该命令会netstat -a显示TIME_WAIT状态中存在大量套接字连接.

我的假设是,如果套接字处于TIME-WAIT状态,并且已使用该SO-REUSEADDR选项设置,则任何尝试使用该端口的新套接字都能够 - 但是,我仍然收到NoRouteToHostException.

它是否正确? 还有什么办法可以解决这个问题吗?

ato*_*ice 52

你试过设置:

echo "1" >/proc/sys/net/ipv4/tcp_tw_reuse
Run Code Online (Sandbox Code Playgroud)

和/或

echo "1" >/proc/sys/net/ipv4/tcp_tw_recycle
Run Code Online (Sandbox Code Playgroud)

这些设置可能会使Linux重新使用TIME_WAIT套接字.不幸的是我找不到任何明确的文件.

  • 对不起,我得说:我爱你! (6认同)
  • 如果某些连接超过负载平衡器,则启用这些将导致问题的强制性警告.请参阅https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html特别是,_当远程主机实际上是NAT设备时,时间戳上的条件将禁止所有除了NAT设备后面的主机在一分钟内连接,因为它们不共享相同的时间戳时钟.有疑问,禁用此选项要好得多,因为它会导致难以检测并且难以诊断问题._ (2认同)

sfu*_*ger 16

这可能有所帮助:

短暂的港口范围

短暂端口范围的另一个重要分支是它限制了从一台机器到远程机器上特定服务的最大连接数!TCP/IP协议使用连接的4元组来区分连接,因此如果短暂端口范围仅为4000端口宽,则意味着一次只能有4000个从客户端计算机到远程服务的唯一连接.

所以也许你的可用端口用完了.要获取可用端口的数量,请参阅

$ cat /proc/sys/net/ipv4/ip_local_port_range 
32768   61000
Run Code Online (Sandbox Code Playgroud)

输出来自我的Ubuntu系统,我有28,232个端口用于客户端连接.因此,只要您拥有280多个客户,您的测试就会失败.


ato*_*ice 9

无法分配请求的地址是EADDRNOTAVAIL错误的错误字符串.

我怀疑你的源端口已经用完了.动态范围中有16,383个套接字可用作源端口(请参阅RFC 2780).150个客户端*100个连接= 15,000个端口 - 因此您可能达到此限制.


Dav*_*ner 5

如果您的源端口不足但实际上没有维护那么多打开的连接,请设置SO_REUSEADDR套接字选项.这将使您能够重用仍处于该TIME_WAIT状态的本地端口.