5

TCPクライアント/サーバー通信の構造は次のとおりです。

  • サーバーの起動時に、サーバーはアクセプタースレッドを開始します。アクセプタースレッドは、クライアント接続を受け入れ、ServerSocketを渡します。
  • クライアント接続が到着すると、アクセプタースレッドはServerSocketでaccept()を呼び出し、クライアント処理ジョブをワーカースレッドに(エグゼキューター/スレッドプールによって)送信し、クライアントソケットを提供します。
  • ループ内のワーカーは、クライアントソケットストリームからデータを読み取り、それを処理して応答を送信します。

問題は、システム全体を適切に停止する方法です。ServerSocketを閉じるだけでアクセプタースレッドを停止できます。これにより、accept()ブロッキング呼び出しがSocketExceptionをスローします。しかし、どのように労働者を止めるのですか?彼らはストリームから読み取り、この呼び出しはブロックされています。これによると、ストリームはInterruptedExceptionをスローしないため、workerをinterrupt()することはできません。

別のスレッドからワーカーソケットを閉じる必要があるようですよね?このためには、ソケットをパブリックフィールドにするか、ワーカーにソケットを閉じるためのメソッドを提供する必要があります。これはいいですか?それとも私のデザイン全体に欠陥があるのでしょうか?

4

3 に答える 3

3

モデルは適切に機能します。IOのような中断できない構造を中断する最良の方法は、ソケットを閉じることです。もちろん、ブロッキング状態になる前にそれを処理することはできますが、IO関数が中断に反応しない場合は、実際には多くの優れたオプションがありません。

于 2011-04-11T15:38:54.633 に答える
2

ワーカーが定期的にチェックするブールフラグを使用することをお勧めします。フラグshouldStopを呼び出し、それがtrueに設定されている場合、ワーカーはクリーンアップしてから死亡します。この方法に従うと、クリーンアップコードを実装できるため、リソースがハングしたままにならないようにすることができます。

于 2011-04-11T15:35:18.107 に答える
2

単にサーバーを停止してはいけません。整合性を確保する必要があるため、クリーンアップの実行中にシャットダウンプロセスに時間がかかる場合があります。

データベースサーバーを想像してみてください。トランザクションの実行中に単にシャットダウンすると、データに一貫性がなくなる可能性があります。そのため、通常、サーバーのシャットダウンには時間がかかります。

  • まず、サーバーでの新しい接続の受け入れを停止する必要があります。
  • 次に、現在のワーカースレッドが作業を終了するのを待ってから、サーバーを閉じて正式にシャットダウンすることができます。
  • または、ワーカースレッドにクライアントとの接続を強制的に閉じさせます(おそらく 、提案され
    ているような何らかのフラグを使用します)。
    これは、データの一貫性を保つためのクリーンアップを意味する場合があります。たとえば、トランザクションを元に戻したり、ファイルやメモリで行ったあらゆる種類の変更を行ったりします。

サーバー側のクライアントとの接続を閉じると、私が理解している限り、クライアントはクライアント側でEOFを取得するはずです。

[編集-1]

しばらくソケットを使用していなかったという理由と、質問が面白いと思ったという理由で、この問題について少し掘り下げました。他の人からよく指摘されているように、唯一のオプションはソケットを閉じることです。これにより、Javadocは入力ストリームと出力ストリームを自動的に閉じます。

スレッドがIOブロックされていないが、待機状態またはスリープ状態にある可能性がある場合でも、特定のソケットの対応するワーカースレッドに対してThread.interrupt()を発行することをお勧めします。すべてのスレッドの状態がブロックされていることを確認できないためです。

public static class IOServerWorker implements Runnable{

        private Socket socket;

        public IOServerWorker(Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            String line = null;
            try{
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while( (line = reader.readLine())!=null){
                    System.out.println(line);
                }
                reader.close();
            }catch(IOException e){
                //TODO: do cleanup here
                //TODO: log | wrap | rethrow exception
            }
        }
    }
于 2011-04-11T15:38:16.957 に答える