web-dev-qa-db-ja.com

NoRouteToHostExceptionを回避する方法は?

開示:私が取り組んでいるコードは大学の授業用です。

背景:完了しようとしているタスクは、さまざまなスレッド化手法の効果について報告することです。これを行うために、Java Sockets。を使用してクライアントからの要求に応答するいくつかのクラスを作成しました。アイデアは、要求でサーバーをあふれさせ、異なるスレッド戦略がこれに対処する方法について報告することです。それぞれクライアントは100個のリクエストを行い、各反復で、何かが壊れるまでクライアントの数を50個増やします。

問題:繰り返し、一貫して、例外が発生します。

原因:Java.net.NoRouteToHostException:要求されたアドレスを割り当てることができません
 Java.net.PlainSocketImpl.socketConnect(Native Method)
 at Java.net.PlainSocketImpl.doConnect(PlainSocketImpl .Java:333)

これは、クライアントとサーバーの両方がローカルホストで実行されている場合など、いくつかのシナリオで発生します。接続はしばらくの間正常に行われますが、150個のクライアントを接続しようとするとすぐに例外がスローされます。

私が最初に考えたのは、オープンファイル記述子に関するLinuxの制限(1024)かもしれないということでしたが、そうは思いません。また、ソケット間のすべての接続が適切に閉じられていることも確認しました(つまり、正しいfinallyブロック内)。

どの部分が最も関連性が高いかわからないため、コードを投稿するのをためらっています。また、問題のコードの膨大なリストを持ちたくないのです。

これに出会った人はいますか? NoRouteToHostExceptionを回避するにはどうすればよいですか?


編集(さらに質問は斜体で示しています)

これまでのところ、The Ephemeral Port RangeまたはRFC 2780のいずれかを指し示すいくつかの良い答えがあります。どちらも、開いている接続が多すぎることを示唆しています。両方の場合、この制限に達するために必要な接続の数は、ある時点で接続を閉じていないことを示唆しています。

クライアントとサーバーの両方をデバッグすると、両方がメソッド呼び出しmyJava-Net-SocketInstance.close()をヒットすることが確認されています。これは、接続が閉じられていることを示します(少なくとも例外的でない場合)。 これは正しい提案ですか?

また、ポートが再び利用可能になるのに必要なOSレベルの待機はありますか?短い期間を必要とする場合は、50以上のクライアントごとにプログラムを個別に実行する可能性があります(または次の試行を実行する前に、楽観的に、コマンドを実行します)。


EDIT v2.0

適切な回答が得られたので、クライアントで作成されたすべてのSocket接続でメソッドsetReuseAddress(true)を使用するようにコードを変更しました。これには期待した効果がありませんでしたが、私はまだ250-300クライアントに制限されています。プログラムが終了した後、コマンドnetstat -aを実行すると、TIME_WAITステータスのソケット接続が多数あることがわかります。

私の仮定は、ソケットがTIME-WAITステータスにあり、SO-REUSEADDRオプションで設定されていた場合、そのポートを使用しようとする新しいソケットは可能になるということでした-しかし、私はまだ受信していますNoRouteToHostException。

これは正しいですか?この問題を解決するためにできることは他にありますか?

59
Grundlefleck

設定を試みましたか:

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

および/または

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

これらの設定により、LinuxでTIME_WAITソケットが再利用される場合があります。残念ながら、決定的なドキュメントは見つかりません。

52
atomice

これは役立つかもしれません:

一時ポート範囲

一時ポート範囲の別の重要な影響は、1台のマシンからリモートマシン上の特定のサービスへの接続の最大数を制限することです! TCP/IPプロトコルは、接続の4タプルを使用して接続を区別します。そのため、一時ポート範囲が4000ポート幅しかない場合、クライアントマシンからリモートサービスへの一意の接続は一度に4000までしか存在できないことを意味します。

したがって、使用可能なポートが不足している可能性があります。使用可能なポートの数を取得するには、を参照してください

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

出力は、クライアント接続用の28,232個のポートがあるUbuntuシステムからのものです。したがって、280以上のクライアントがあるとすぐにテストが失敗します。

16
sfussenegger

要求されたアドレスを割り当てることができませんは、EADDRNOTAVAILエラーのエラー文字列です。

送信元ポートが不足していると思われます。ソースポートとして使用できるダイナミックレンジには16,383個のソケットがあります( RFC 278 を参照)。 150クライアント* 100接続= 15,000ポート-したがって、おそらくこの制限に達しています。

9
atomice

ソースポートが不足しているが、実際にその数の開いている接続を維持していない場合は、SO_REUSEADDRソケットオプションを設定します。これにより、TIME_WAIT状態のままのローカルポートを再利用できます。

5
David Joyner

1秒あたり500接続を閉じると、ソケットが不足します。キープアライブを使用する同じ場所(Webサーバー)に接続している場合は、接続プールを実装できるため、ソケットを閉じたり開いたりすることはありません。

これによりCPUも節約されます。

Tcp_tw_recycleとtcp_tw_reuseを使用すると、以前の接続からパケットが着信する可能性があります。そのため、パケットがクリアされるまで1分間待機します。

1
user190941

この質問に出くわした他のJavaユーザーについては、接続が適切に再利用されるように接続プールを使用することをお勧めします。

0
Bryan Larson