次のような Discover プロセスを実装しています。
- UDP ソケットを開いて、特定のポートでブロードキャスト応答をリッスンします
- いくつかのリクエストを送信します(後で応答を期待します)
- 一定時間後に UDP ソケットを閉じる
最初の呼び出しは機能します。しかし、他の呼び出しではバインド エラーが発生します。アドレスは既に使用されています: bind
Windows 7 を実行しています。いくつかのテストを行ったところ、channel.close(); の後にそれが見つかりました。Netstat はまだ提供します:
netstat -a -b -sp udp | grep 55224
UDP 0.0.0.0:55224 :
したがって、UDP ポートは OS レベルで開かれたままです。
Web を検索しましたが、OS レベルでのリークである可能性があります。いくつかの Java Datagram Socket の質問
NIO チャネルを使用するテストと使用しないテストの 2 つを実行しました (Web で見つかったテストから)。NIO バージョンでエラーを再現しましたが、NIO を使用しなくても機能します。
私は誰でも、NIO で動作させる方法を教えてくれます。対象となるプラットフォームは Android でt wan
、常にブロードキャストをリッスンするわけではありませんが、繰り返しの期間だけリッスンします。
テストソケット
public void testConnectCloseWithSocket() {
long tCumulative = 0;
int errAt = -1;
System.out.println("start...");
for (int i = 0; i < 4000; i++) {
try {
errAt = i;
DatagramSocket result = new DatagramSocket(null);
result.bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
result.close();
//success at last
tCumulative = 0;
} catch (Exception e) {
System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage());
tCumulative+=50;
try {
Thread.sleep(50);
} catch (InterruptedException e1) {
}
i--;
}
}
System.out.println("end...");
}
結果ソケット<
start... エラー (at=1319) (waited=0ms): アドレスは既に使用されています: バインドできません
エラー (at=1438) (waited=0ms): アドレスは既に使用されています: バインドできません
エラー (at=1587) (waited=0ms): アドレスは既に使用されています: バインドできません
エラー (at=1740) (waited=0ms): アドレスは既に使用されています: バインドできません
終わり...
いくつかのエラーが発生しましたが、ソケットは適切に閉じられます...これは私のニーズに合っています
チャンネルでテスト
public void testConnectCloseWithChannel() {
long tCumulative = 0;
int errAt = -1;
System.out.println("start...");
for (int i = 0; i < 4000; i++) {
try {
errAt = i;
Selector selector = Selector.open();
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
channel.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
clientKey.cancel();
channel.close();
//success at last
tCumulative = 0;
} catch (Exception e) {
System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage());
tCumulative+=50;
try {
Thread.sleep(tCumulative);
} catch (InterruptedException e1) {
}
i--;
}
}
System.out.println("end...");
}
注: channel.register がコメント化されている場合、テストは機能します ..
チャネルの結果
start... エラー (at=0) (waited=0ms): null エラー (at=0) (waited=50ms): アドレスは既に使用されています: bind
エラー (at=0) (waited=100ms): アドレスは既に使用されています: bind
エラー (at=0) (waited=150ms): アドレスは既に使用されています: bind ...
助けてくれてありがとう