3

Javaベースのサーバーを作成しています。

着信メッセージを受け入れるためにサーバーソケットを使用しています。

ただし、プログラム内のある時点で、サーバーソケットが別のポートをリッスンするようにします。

サーバーソケットを閉じます。そして、私の新しいポートで新しいポートを開始します。すべて順調。

ただし、サーバーソケットを以前のポートに再度変更すると、エラーが発生します。

サーバーソケットを閉じた後、しばらくの間タイムアウト状態のままであるということを読みました。

だからここに私の質問があります:サーバーソケットのこのタイムアウト状態を回避し、ポートを閉じて同じポートをもう一度聞きたい後に、ポートを再び使用可能にすることはできますか?


編集:サーバーソケットを作成してリッスンする関数と、サーバーソケットを無効にして、直後に新しいソケットを作成する関数

public void makeServerSocketWithPort(int portnr) throws IOException, Exception
{
    server = new ServerSocket(portnr);
    server.setReuseAddress(true);
    while(!portchanged)
    {
        Socket sock = server.accept();
        System.out.println(server.getLocalPort());
        System.out.println(sock.getLocalPort());
        handler = new Requesthandler(sock); //should be in a thread
        System.out.println(server.getLocalPort());
        System.out.println(sock.getLocalPort());
    }

}

public void invalidateRequestHandler(int newPort)
{   
    if(server != null)
    {
       portchanged = true; 
        try {
            server.close();
        } catch (IOException ex) {
            Logger.getLogger(Controlserver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    portchanged = false;
    makeServerSocketWithPort(newPort);
}

エラーStackTrace:

Exception in thread "main" java.net.SocketException: Socket closed
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
at java.net.ServerSocket.implAccept(ServerSocket.java:462)
at java.net.ServerSocket.accept(ServerSocket.java:430)
at stuff.Controlserver.makeServerSocketWithPort(Controlserver.java:63)
at stuff.Main.main(Main.java:44)

編集:無駄にそれを修正するための2番目の試み:

public void makeServerSocketWithPort(int portnr, boolean invalidated) throws IOException, Exception
{
    if(!invalidated)
    {
        server = new ServerSocket();
        server.setReuseAddress(true);
        server.bind(new InetSocketAddress(portnr));

        portchanged = false;
    }
    else
    {
        //TODO: invalidate the old requestHandler
        if(server != null)
        { 
            try 
            {
                server.close();
                server = null;
            } 
            catch (IOException ex) 
            {
                Logger.getLogger(Controlserver.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if(server.isClosed())
        {
            System.out.println("closed biatch!");
        }
        else
        {
            System.out.println("surprise moddafakkaaaaa!!!");
        }

        //---------------------------------------------
        //then make new requestHandler with new port
        portchanged = true;
    }

    while(!portchanged)
    {
        if(server != null && !server.isClosed() && !invalidated)
        {
            Socket sock = server.accept();
            System.out.println(server.getLocalPort());
            System.out.println(sock.getLocalPort());
            System.out.println("test");
            handler = new Requesthandler(sock); //should be in a thread
            handler.start();
            System.out.println("ja harm");
            System.out.println(server.getLocalPort());
            System.out.println(sock.getLocalPort());
        }
        else
        {
            portchanged = true;
        }
    }

    if(portchanged)
    {
        portchanged = false;
        makeServerSocketWithPort(portnr, false);
    }
}

繰り返しますが、これは正常に機能します。HTMLページをナビゲートできます。Webページの1つを介してポート番号を変更すると、ポート番号は適切に保存され、ストレージxmlファイルに変更されます。しかし、ソケットを変更して、そのソケットを介してページにすぐに移動すると、ソケットが閉じられており、アプリケーションを再起動するまで機能しないと表示されます。

私はまだこの再起動を回避する方法を探しています。


さて、謎を解きました。スレッドをもう少しうまくサポートするために、クラスを少し再構築する必要がありました。ソケットを閉じてから新しいスレッドを作成する代わりに、新しいスレッドを開始してからソケットを閉じました。少しいじった後、それはうまく機能しているように見えました。

返信などをありがとう。

4

2 に答える 2

2

TCPviewを使用して、システムで開いているすべてのポートを確認します。使用中のポートを閉じることができます。

于 2012-12-12T11:45:56.690 に答える
2

これは、OSによる通常のサーバーソケットの動作です。OSは、ポートをWAIT_TIMEOUT状態で開いたままにします。これを回避するには、を使用してみてください ServerSocket.setReuseAddress(boolean on)SO_REUSEADDRこれにより、ソケットオプション が有効/無効になります。ドキュメントについては、こちらを確認してください。

メソッドのjavadocを引用するsetReuseAddress

TCP接続が閉じられると、接続が閉じられた後、接続が一定期間タイムアウト状態のままになる場合があります(通常はTIME_WAIT状態または2MSL待機状態と呼ばれます)。既知のソケットアドレスまたはポートを使用するアプリケーションの場合、ソケットアドレスまたはポートに関連するタイムアウト状態の接続があると、必要なSocketAddressにソケットをバインドできない場合があります。

bind(SocketAddress)を使用してソケットをバインドする前にSO_REUSEADDRを有効にすると、前の接続がタイムアウト状態であっても、ソケットをバインドできます。

于 2012-12-12T11:14:25.013 に答える