2016-12-31 4 views
2

私はソケット接続を処理するスレッドを持っている:ソケット接続を処理するスレッドを終了するには?

BufferedReader socketInput = new BufferedReader(new InputStreamReader(mySocket.getInputStream())); 
while (true) 
{ 
    String line = socketInput.readLine(); 
    // do stuff 
} 

私はこのサイトには、いくつかの答えを読んでてきたように、推奨される解決策は一つのスレッドのセットと私(ソケットハンドリング)スレッドフラグを使用することですそのフラグが状態を変更すると、自身をチェックして終了します。ような何か:readLine()はまだ入力を待っているとき

while (!done) 
{ 
    String line = socketInput.readLine(); 
    // do stuff 
} 

は、しかし、これははまり込むことができます。私はタイムアウトを設定することができると思います。おそらく動作しますが、私はまだ私のスレッドの前に100ミリ秒の遅延になるだろう

mySocket.setSoTimeout(100); 
while (!done) 
{ 
    String line = socketInput.readLine(); 
    // do stuff 
} 

は「実現」フラグの状態が変更されました。

すぐにスレッドを「実現」する方法はありますか?そうでない場合は、私の解決策(タイムアウトとフラグdone)は正しいですか?

編集:socketInputのタイプがBufferedReaderであることを明確にしました(あるいは、私はScannerと考えています)。

+0

はhttp://stackoverflow.com/questions/12315149/interrupt-stop-thread-with-socket-ioも参照してください。 -blocking-operation – Matthieu

+0

私の答えを編集して、チャネルを使った非同期I/Oがそれほど大したことではないことを証明しようとしました。私はあなたがそれが面白いと幸せな新年を見つけることを願っています! :) – Matthieu

答えて

0

ソケット接続を完了するときに何かを試してみる最善の方法。あなたはソケット接続

byte[] data = new byte[2048]; 
while (!done) { 
    int count = input.read(data); 
    if (count <= 0) { 
     if (count < 0) 
      done = true; 
     continue; 
    } 
    String request = new String(data, 0, count); 
    //do stuff 
} 

をthreadling終了できる場合は読みメソッドの戻り値-1私たちは、カウントが== -1、ソケットクライアントは現在接続されていない場合、我々はの値を変更することで、ループを終了することができ、入力で何かを読み取ろう完了しました。

+0

私は私が従うかどうかわからない - 私のスレッドが終了するためにあなたの解決策は接続の反対側を終了する必要がありますか?私の側からの接続を終了したいのですが? – NPS

2

解決策は正しいです。完了するとtrueに設定されます。 そして、readLineは常に100ms待つでしょう。あなたが待っていない場合はthread.interrupt()を呼び出してスレッドを中断するかもしれませんが、それはあまりクリーンではありません。

+0

私はソケットとマルチスレッドのプログラミングを学んでいるので、きれいなソリューション(と効率的なもの)は私が目指しているものです。だから、あなたが言っているのは、 'java.io'ではすぐにスレッドを終了することが不可能で、代わりに' java.nio'を使用しなければなりませんか?そしてあなたが提供したリンク: 'sel.select(100)' - これは私のコードと同じですか?何かをする前に100ミリ秒待ちますか? – NPS

+0

あなたは100mも待っているsel(100)です。 –

+0

Javadoc https://docs.oracle.com/javase/7/docs/api/java/nio/channels/Selector.html#select(long)には、Object.wait(long)を使用して待機が行われると記載されていると思いますselector.notify()を使用してスレッドに通知することができます。ここに待機/通知のドキュメントがあります:http://stackoverflow.com/documentation/java/145/object-class-methods-and-constructor/619/wait-and-notify-methods#t=201612311301369525337 –

3

これを処理する最も一般的な方法は、もう一方のスレッドからソケットを閉じることです。これにより、読み込み側がブロックを解除し、ソケットが閉じられた(期待された)エラーで終了します。使用可能なソケットAPIによっては、読み取り側のみをシャットダウンすることもできます。 JDK shutdownInput()の短い見方からは動作するかもしれません。

しかし、後でこれらのソケットから読み続ける場合は、これらの問題は解決しません。あなたのソリューションはそこで動作するはずですが、基本的に100msすべてのソケットをポーリングするので、性能と反応性は明らかに悪いです。

+0

もちろん、私は100ミリ秒をもっと短いものに調整しようとすることができます。しかし、それを行うより良い方法はありますか?私は後でソケットを使い続けたいと思う。また、私は他の側からの接続を閉じることができないと仮定します(それは私の制御から外れているか、または他の何らかの理由で)。 – NPS

+0

100msよりも下回ると、スレッドの不必要な中断が発生します(毎回例外がスローされる)ので、高速停止とオーバーヘッドのトレードをトレードします。通常は、読み込みを停止し、後で読むために再開するためのユースケースがないため、closeで十分です。誰かが一時的に読み込みを停止したい場合、彼は再びデータに興味があるまで、ソケット上で[line]を読み上げることはありません。特別なシナリオがありますか? – Matthias247

+0

私は、あるスレッドがソケットに対して読み書きをする場合を念頭に置いていました。通常、いくつかのデータの 'read'を待っていますが、(外部から)ソケットに書き込むデータを取得するときには、listenを停止し、データをソケットに書き込み、' read'を待つ必要があります。 – NPS

2
  1. セレクタを作成読むためにいくつかのデータがある場合ので、あなたはreadLine()(つまりを呼び出すことができます返されますselect()方法あなたのセレクターを呼び出しSelectionKey.OP_READ
  2. でセレクタにnon-blockingregister itにごsocket.getChannel()を設定select()リターン> 0

あなたのソケット処理を終了したいときはいつでも、あなたのを設定フラグをつけて、セレクタwakeup()を呼び出してください。これにより、すぐにselect()が返されます(潜在的に0、またはアクティビティがあった場合は1)。 doneフラグを確認してスレッドを正常に終了することができます。

ここには簡単な実装があります。私はあなたがそれを閉じなければならないスレッドでそれを開いているかのように引数としてBufferedReaderを渡します。これもまたソケットを閉じるので、外部で行う必要があります。優雅にデータを送信するための入力と1つの処理を停止するためのスレッドを通知するための2つの方法があります。

public class SocketHandler extends Thread { 

    private Socket sok; 
    private BufferedReader socketInput; 

    private Selector sel; 
    private SocketChannel chan; 
    private boolean done; 

    public SocketHandler(Socket sok, BufferedReader socketInput) throws IOException { 
     this.sok = sok; 
     chan = sok.getChannel(); 
     chan.configureBlocking(false); 
     sel = Selector.open(); 
     chan.register(sel, SelectionKey.OP_READ); 
     this.socketInput = socketInput; 
     done = false; 
    } 

    @Override 
    public void run() { 
     while (!done) { 
      try { 
       if (sel.select() == 0) 
        continue; 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      // Only one channel is registered on only one operation so we know exactly what happened. 
      sel.selectedKeys().clear(); 
      doRead(); 
      // Otherwise: loop through sel.selectedKeys(), check for readability and clear the set 
     } 
     try { 
      sel.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void doRead() { 
     try { 
      String line = socketInput.readLine(); 
      // TODO: process 'line' 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void signalStop() { 
     done = true; 
     if (sel != null) 
      sel.wakeup(); // Get out of sel.select() 
    } 

    public void doWrite(byte[] buffer) throws IOException { // Or "String message" 
     sok.getOutputStream().write(buffer); // Or anything else 
    } 

} 
関連する問題