Java 如何避免 NoRouteToHostException?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1572215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 15:01:06  来源:igfitidea点击:

How to avoid a NoRouteToHostException?

javanetworkingsocketsexception-handling

提问by Grundlefleck

Disclosure: the code I'm working on is for university coursework.

披露:我正在编写的代码用于大学课程。

Background: The task I'm trying to complete is to report on the effect of different threading techniques. To do this I have written several classes which respond to a request from a client using Java Sockets. The idea is to flood the server with requests and report on how different threading strategies cope with this. Each client will make 100 requests, and in each iteration we're increasing the number of clients by 50 until something breaks.

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

Problem: repeatably, and consistently, an exception occurs:

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

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

This happens in several scenarios, including when both the client and server are running on localhost. Connections can be made successfully for a while, it's soon after trying to connect 150 clients that the exception is thrown.

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

My first thought was that it could be Linux's limit on open file descriptors (1024) but I don't think so. I also checked that any and all connections between the sockets are closed properly (i.e. within a correct finallyblock).

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

I'm hesitant to post the code because I'm not sure which parts would be the most relevant, and don't want to have a huge listing of code in the question.

我对发布代码犹豫不决,因为我不确定哪些部分最相关,并且不想在问题中列出大量代码。

Has anyone come across this before? How can I avoid the NoRouteToHostException?

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



EDIT (further questions are italicised)

编辑(其他问题用斜体表示)

Some good answers so far which point to either the The Ephemeral Port Range or RFC 2780. Both of which would suggest that I have too many connections open. For both it appears the number of connections which need to be made to reach this limit suggest that at some point I'm not closing connections.

到目前为止,有一些很好的答案指向临时端口范围或 RFC 2780。这两者都表明我打开了太多连接。对于这两种情况,似乎需要建立的连接数才能达到此限制表明在某些时候我不会关闭连接。

Having debugged both client and server, both have been observed to hit the method call myJava-Net-SocketInstance.close(). This would suggest that connections are being closed (at least in the non-exceptional case). Is this a correct suggestion?

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

Also, is there an OS level wait required for ports to become available again?It would be a possibility to run the program a separate time for each 50+ clients if it would just require a short period (or optimistically, running a command) before running the next attempt.

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



EDIT v2.0

编辑 v2.0

Having taken the good answers provided, I modified my code to use the method setReuseAddress(true) with every Socket connection made on the client. This did not have the desired effect, and I am still limited to 250-300 clients. After the program terminates, running the command netstat -ashows that there is a lot of socket connections in the TIME_WAIT status.

接受了提供的好答案后,我修改了我的代码,以对客户端上建立的每个 Socket 连接使用 setReuseAddress(true) 方法。这并没有达到预期的效果,我仍然仅限于 250-300 个客户端。程序终止后,运行命令netstat -a显示有很多处于TIME_WAIT状态的socket连接。

My assumption was that if a socket was in the TIME-WAITstatus, and had been set with the SO-REUSEADDRoption, any new sockets attempting to use that port would be able to - however, I am still receiving the NoRouteToHostException.

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

Is this correct?Is there anything else which can be done to solve this problem?

这样对吗?还有什么办法可以解决这个问题吗?

回答by atomice

Cannot assign requested address is the error string for the EADDRNOTAVAIL error.

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

I suspect you are running out of source ports. There are 16,383 sockets in the dynamic range available for use as a source port (see RFC 2780). 150 clients * 100 connections = 15,000 ports - so you are probably hitting this limit.

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

回答by sfussenegger

This may help:

这可能有帮助:

The Ephemeral Port Range

临时端口范围

Another important ramification of the ephemeral port range is that it limits the maximum number of connections from one machine to a specific service on a remote machine! The TCP/IP protocol uses the connection's 4-tuple to distinguish between connections, so if the ephemeral port range is only 4000 ports wide, that means that there can only be 4000 unique connections from a client machine to a remote service at one time.

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

So maybe you run out of available ports. To get the number of available ports, see

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

$ cat /proc/sys/net/ipv4/ip_local_port_range 
32768   61000

The output is from my Ubuntu system, where I'd have 28,232 ports for client connections. Hence, your test would fail as soon as you have 280+ clients.

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

回答by David Joyner

If you're running out of source ports but aren't actually maintaining that many open connections, set the SO_REUSEADDRsocket option. This will enable you to reuse local ports that are still in the TIME_WAITstate.

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

回答by atomice

Have you tried setting:

您是否尝试过设置:

echo "1" >/proc/sys/net/ipv4/tcp_tw_reuse

and/or

和/或

echo "1" >/proc/sys/net/ipv4/tcp_tw_recycle

These settings may make Linux re-use the TIME_WAIT sockets. Unfortunately I can't find any definitive documentation.

这些设置可能会使 Linux 重新使用 TIME_WAIT 套接字。不幸的是,我找不到任何权威文档。

回答by Bryan Larson

For any other Java users that stumble across this question, I would recommend using connection pooling so connections are reused properly.

对于偶然发现此问题的任何其他 Java 用户,我建议使用连接池,以便正确重用连接。

回答by user190941

If you are closing 500 connection per second you will run out of sockets. If you are connecting to the same locations (web servers) that use keepalive you can implement connection pools, so you don't close and reopen sockets.

如果您每秒关闭 500 个连接,则会耗尽套接字。如果您连接到使用 keepalive 的相同位置(Web 服务器),您可以实现连接池,这样您就不会关闭和重新打开套接字。

This will save cpu too.

这也将节省cpu。

Use of tcp_tw_recycle and tcp_tw_reuse can result in packets coming in from the previous connecction, that is why there is a 1 minute wait for the packets to clear.

使用 tcp_tw_recycle 和 tcp_tw_reuse 会导致数据包从之前的连接进入,这就是为什么要等待 1 分钟才能清除数据包。