web-dev-qa-db-ja.com

「Java.net.BindException:アドレスは既に使用されています」負荷テストのためにソケットを迅速に作成および破棄しようとしたとき

私はJavaサーバーへの多数のソケット接続を開き、認証し、接続を閉じてから繰り返します。サーバーをロードテストしようとしています。 :

Java.net.BindException:すでに使用されているアドレス:接続

私が読んだ文書によると、この理由は、close()が呼び出された後、閉じられたソケットがしばらくの間、割り当てられたローカルアドレスを占有しているためです。これはOSに依存しますが、数分のオーダーになる場合があります。 setReuseAddress(true)が呼び出された直後にそのアドレスが再利用可能になることを期待して、ソケットでclose()を呼び出してみました。残念ながら、これは事実ではないようです。

ソケット作成の私のコードは次のとおりです。

Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect(new InetSocketAddress(m_Host, m_port));

しかし、私はまだこのエラーを受け取ります:

Java.net.BindException:すでに使用されているアドレス:しばらくしてから接続します。

私がやろうとしていることを達成する他の方法はありますか?たとえば、100個のソケットを開き、すべてを閉じ、200個のソケットを開き、すべてを閉じ、300個を開くなど、最大で2000個程度のソケットを作成します。

どんな助けも大歓迎です!

27
bradforj287

2分間のTIME_WAIT期間内にその数の送信ソケットを開くことにより、送信ポートのスペースを使い果たしています。自問すべき最初の質問は、これが現実的な負荷テストであるかどうかです。実際のクライアントは本当にそうするのでしょうか?そうでない場合は、テスト方法を修正するだけです。

BTW SO_LINGERは、データがフラッシュされるのをclose()中にapplicationが待機する秒数です。通常はゼロです。これがクローズを発行した終了である場合、ポートはとにかくTIME_WAIT間隔の間ハングアップします。これは同じことではありません。 SO_LINGERオプションを悪用して問題にパッチを当てることができます。ただし、それはピアで例外的な動作も引き起こすため、これもテストの目的ではありません。

20
user207421

Bind()を使用せずにsetReuseAddress(true)を使用するのはおかしいです。setReuseAddress(およびそのポイント)の意味を理解してください。 100-2000はnot多数のソケットを開くことはできませんが、接続しようとしているサーバーは(同じaddr/portペアに見えるため) )、通常のバックログ50でそれらをドロップする場合があります。

編集:複数のソケットをすばやく開く必要がある場合(ermmポートスキャン?)、very NIOとconnect()/ finishConnect()+ Selectorの使用を強くお勧めします。同じスレッドで1000個のソケットを開くのは非常に遅いです。コードのどちらの方法でもfinishConnect()が必要な場合があることを忘れていました。

1
bestsss