2016-09-14 4 views
0

私はこの方法でソケットとスレッドを使い慣れています。メインスレッドのソケットをリッスンしているときのスレッド読み込みコンソールの入力

ユーザ入力を待っているスキャナと同時にソケット通信を待っている入力ストリームリーダーで問題が発生しています。私のプログラムはクライアント/サーバシステムと通信しようとしていますが、それはうまくいきますが、スキャナなどで直接コンソールにコマンドを入力したいと思っています。しかし、メインスレッドのwhileループはソケット通信のためにブロックしていますが、スキャナはinputThreadのwhileループでブロックしています。

私の問題は、サーバーを閉じるためにコンソールでコマンドを送信すると(ブール '実行中'をfalseに設定すると)、メインスレッドのwhileループはソケット通信入力を待機します。メッセージを受信すると、ブール '実行中'がfalseに設定されているため、whileループから脱出しますが、whileの条件をチェックする前にメッセージを待っているためにメッセージが送信されます。

私の他の問題は基本的に同じ概念ですが、inputThreadのwhileループの内部です。メインスレッドのwhileループが壊れた場合、入力スレッドはユーザー入力を受け取るまでスキャナーをブロックします。ユーザー入力を受け取ると、スレッドが中断されてwhileループから脱出します(whileループの条件付き)。

私のプログラムが終了するためには、プログラムを正しく終了させるためにどちらかの方法で送信したいときに、ソケットとユーザー入力から "restart server"メッセージを送信する必要があります。

どうすればこの問題を解決できますか?私は、サーバーを終了するソケットを受け取ったときスキャナのブロックをキャンセルすると仮定したいと思いますが、どうすればいいですか?これを行うもっと良い方法があるような気がします。

コード:

inputThread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     Logger.log("Starting input thread..."); 
     while(!Thread.currentThread().isInterrupted()) { 
      try { 
       scanner = new Scanner(System.in); 
       String reply = runCommand(scanner.nextLine()); 
       Logger.log(reply); 
       if(reply.equals("server restarted")) { 
        // TODO: Cancel socket input blocking? 
       } 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     Logger.log("Closing input thread..."); 
    } 
}); 
inputThread.start(); 
ServerSocket socket = null; 
InputStreamReader inputStream = null; 
BufferedReader input = null; 
try { 
    int port = getPort(); 
    socket = new ServerSocket(port); 
    Logger.log("Server running on port " + port); 
    while(running) { 
     connection = socket.accept(); 
     inputStream = new InputStreamReader(connection.getInputStream()); 
     input = new BufferedReader(inputStream); 
     String reply = runCommand(input.readLine()); 
     if(reply.equals("server restarted")) { 
      // TODO: Cancel scanner input blocking? 
     } 
     reply(reply); 
    } 
} catch(Exception e) { 
    e.printStackTrace(); 
} finally { 
    if(socket != null) { 
     try { 
      socket.close(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    if(connection != null) { 
     try { 
      connection.close(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    if(inputStream != null) { 
     try { 
      inputStream.close(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    if(input != null) { 
     try { 
      input.close(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    if(response != null) { 
     try { 
      response.close(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
inputThread.interrupt(); 

は、最初の問題はServerSocket::acceptコールで

+0

これはあなたを助けるかもしれません:http://tutorials.jenkov.com/java-nio/nio-vs-io.html#blocking-vs-non-blocking – Leon

+0

inputThreadでは、中断した状態をチェックし、メインで中断します、 ここまでは順調ですね。しかし、あなたはtry/catchでスキャナーのブロッキングコールを囲んでいました。したがって、スレッドが中断された場合、InterruptedExceptionがキャッチされ、**中断された状態がリセットされます**。したがって、InterruptedExceptionの前に(!Exceptionの前に)catchブロックを追加し、inputThreadの中断状態を再度設定する必要があります。また、割り込みのチェックだけでなく、疑似割り込みが発生する可能性があるため、チェックする追加の条件が必要です。 – Fildor

+0

参照:https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html – Fildor

答えて

0

をお読みいただきありがとうございました。ブロックしていますが、割り込みに反応しません(InterruptedExceptionをスローすると宣言されている場合)。すぐにブロックを解除する方法は、他のスレッドからソケットをcloseに送信することです。 accept()コールはすぐにSocketExceptionをスローします。

2番目の問題は実際に解決するのが簡単です。whileループはrunningフラグもチェックする必要があります。したがって、プログラムを停止するためにコマンドライン入力が与えられた場合、入力スレッドは次のコマンドの待機を開始しません。

関連する問題