Windows で別のプロセスが既にバインドされているソケットに Java アプリがバインドされないようにするにはどうすればよいですか?
ポート 80 でリッスンしている Java アプリケーションがあるという問題があります。アプリケーションは正常に起動し、例外は報告されません。ポート 80 に接続できなかった理由がわかりませんでした。他のポートは正常に機能していました。80 でリッスンしている他のプロセスの netstat を確認したところ、Skype が見つかりました。私はそれが可能だとは思いませんでしたが、いくつかの調査の結果、Skype は SO_REUSEADDR オプションでリッスンしていると推測しています。この状態では受理申請は不定です。このインスタンスで Java アプリケーションがバインド例外 (またはその他) で失敗することを望みます。
Java 経由でそのオプションにアクセスできれば SO_EXCLUSIVEADDRUSE を使用できるように見えますが、それは可能ではないと思います。SO_REUSEADDR に関する多くの質問と回答がありますが、私の質問に答えるものは見つかりませんでした。これは Skype だけの問題ではありません (リスニング部分をオフにすることができます)。この状況でプログラムをより堅牢にしたいと考えています。
これは、Windows 7 ボックスでの netstat -abn のスニペットです。
Proto Local Address Foreign Address State
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING [java.exe]
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING [Skype.exe]
これが、Skype が SO_REUSEADDR を使用していると想定している理由です。
プロセスは、異なるインターフェイスでリッスンしているようには見えません。
コードのスニペットを次に示します。ポートは 80 です。
myServerSocket = new ServerSocket(myTcpPort);
while (true) {
new HTTPSession( myServerSocket.accept(), threadPool );
}
さらに詳しい情報として、副作用や誤ったメッセージの処理を最小限に抑えるためのサンプル プログラムを作成しました。
import java.net.ServerSocket;
public class PortTest
{
public static void main(String[] args)
{
System.out.println( "Hit Ctrl-C to stop.\n" );
try {
ServerSocket myServerSocket = new ServerSocket(80);
System.out.println( "Before the accept() call.");
myServerSocket.accept();
System.out.println( "After the accept() call." );
}
catch (Exception ex ) {
System.out.println("Error listening.");
ex.printStackTrace();
}
}
}
このサンプル プログラム (PortTest) を実行しても、Skype が実行されていてポート 80 でリッスンしている場合でも、例外は発生しません。
Error listening.
java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(Unknown Source)
at java.net.AbstractPlainSocketImpl.bind(Unknown Source)
at java.net.PlainSocketImpl.bind(Unknown Source)
at java.net.ServerSocket.bind(Unknown Source)
at java.net.ServerSocket.<init>(Unknown Source)
at java.net.ServerSocket.<init>(Unknown Source)
at PortTest.main(PortTest.java:10)