2

クライアント (スレッド) がサーバーに接続してデータを取得する Java のクライアント サーバー シミュレーションに取り組んでいます。数秒後、ランダムに選択されたクライアント (スレッド) の 1 つを強制終了する必要があります。サーバーとの通信に使用されているソケットを閉じて、彼を死なせたままにしました(run()メソッドを終了することにより)。問題は、新しく作成されたスレッドが、サーバーに接続するために以前に使用されたものと同じソケット (同じアドレスと同じポート) を作成しようとしている場合です。

java.net.BindException: Address already in use
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:374)
    at java.net.Socket.bind(Socket.java:627)
    at java.net.Socket.<init>(Socket.java:423)
    at java.net.Socket.<init>(Socket.java:319)

ソケットを作成するコード:

private void createNewSocket(InetAddress sIP, int sPort, 
        InetAddress cIP, int cPort) {
    try {
        socket = new Socket(sIP, sPort, cIP, cPort);
    } catch (IOException e) {
        e.printStackTrace();
        System.err.println("Socket unsuccessfully created");
    }
    try {
        in = new BufferedReader(new InputStreamReader(
                socket.getInputStream()));

        out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                socket.getOutputStream())), true);

    } catch (IOException e) {
        e.printStackTrace();    
        try {
            socket.close();
        } catch (IOException e2) {
            System.err.println("Socket unsuccessfully closed");
        }
    }
}

public void run() {

    createNewSocket(gprsServerIP, Util.PORT_SERVER_PORT,
            clientIP, sendPort);

    out.println(REQUEST);   
    try {
        serverPort = Integer.parseInt(in.readLine());   
        TCPClient.serverPort[clientID] = serverPort;
        System.out.println("Server port: " + serverPort + '\n' + 
                            "Send port: " + sendPort + '\n');
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            socket.close();
        } catch (IOException e) {
            System.err.println("Socket unsuccessfully closed");
        }
    }

    while (true) {      

        if (clientID == TCPClient.selectedID) {

            TCPClient.selectedID = -1;

            createNewSocket(gprsServerIP, Util.PORT_SERVER_PORT, 
                    clientIP, sendPort);

            out.println(FREE_PORT + serverPort);
            try {
                socket.close();
            } catch (IOException e2) {
                System.err.println("Socket unsuccessfully closed");
            }
            //System.out.println(socket.isClosed());
            System.out.println("Port:" + serverPort + " is free");
            TCPClient.id[clientID] = -1;
            break;              
        }                           
    }
    clientCount--;

}
4

2 に答える 2

0

プロセスが不自然に終了すると、ポートがすぐにバインド解除されず、ポートが使用可能になるまで数分待たなければならないことがあります。可能であれば、プログラムは正常に失敗する必要があります (つまり、強制終了する必要がある場合でも、シャットダウン フックでソケットを閉じる必要があります)。

于 2012-08-30T22:55:36.717 に答える
0

クライアントソケットがまだ inCLOSE_WAITまたはTIME_WAITstatusである可能性があります。オペレーティング システムは、別のアプリケーションがデータを再利用できるようになる前に、すべてのデータがソケットに配信されていることを確認しています。そうしないと、新しいクライアントが以前の接続から残ったガベージ重複パケットを取得する可能性があります。

クライアントは、一定のポートではなく、さまざまなポートを使用することをお勧めします。次に、範囲内の次のポートを使用し、範囲の終わりに到達するとループします。

ただし、クライアント ポートを設定する必要がない場合は、ポート 0 を に渡して、コードでクライアント ポートを設定しないでくださいSocket。この場合、JDK とオペレーティング システムは正しいことを行い、適切な空きポートを選択します。

ウィキペディアから引用:

CLOSE-WAIT: サーバーは、ローカル アプリケーションから処理が完了したという通知を受け取ります。サーバーはそのフィンをクライアントに送信します。

TIME-WAIT: リモート ピアが接続終了要求の確認応答を受信したことを確認するのに十分な時間が経過するのを待機することを表します。RFC 793 によると、MSL (セグメントの最大有効期間) と呼ばれる最大 4 分間、接続は TIME-WAIT 状態に留まることができます。

于 2012-08-30T23:29:31.147 に答える