web-dev-qa-db-ja.com

Java 1.4でBufferedReaderとPrintWriterのタイムアウトをどのように設定しますか?

ソケット接続を使用して作成されたBufferedReaderとPrintWriterにタイムアウトを設定するにはどうすればよいですか?これが私が今持っているサーバー用のコードで、サーバーかクライアントのどちらかがクラッシュするまで機能します。

while(isReceiving){
    str = null;
    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);

    while ((str = br.readLine()) != null){
        System.out.println("Processing command " + str);
        pw.println(client.message(str));
    }
}

このコードの範囲外で、1000msのソケットタイムアウトを課しました。これは、最初の接続を待機するときに意図したとおりに機能します。しかし、プログラムは(str = br.readLine())でブロックします。クライアントがハングまたはクラッシュした場合、プロセスを終了しない限り、ブロックが停止することはありません(それでも常に機能するとは限りません)。

問題のクライアントコードはこれと非常によく似ており、同様の方法でブロックしています。

14

Socket.close()を呼び出しても、br.readLine()でブロックが中断されないようだったので、少し回避策を実行しました。クライアントをサーバーから切断するとき、私は単に文字列「bye」を送信し、このコマンドを受信したときにソケット接続を閉じるようにサーバーに指示しました。

while ((str = br.readLine()) != null){
    // If we receive a command of "bye" the RemoteControl is instructing
    // the RemoteReceiver to close the connection.
    if (str.equalsIgnoreCase("bye")){
        socket.close();
            break;
    }
    System.out.println("Processing command " + str);
    pw.println(client.message(str));
}
2

GoogleのGuavaライブラリから SimpleTimeLimiter を使用できます。

サンプルコード(Java 8):

BufferedReader br = ...;
TimeLimiter timeLimiter = new SimpleTimeLimiter();

try {
    String line = timeLimiter.callWithTimeout(br::readLine, 10, TimeUnit.SECONDS);
} catch (TimeoutException | UncheckedTimeoutException e) {
    // timed out
} catch (Exception e) {
    // something bad happened while reading the line
}
16
Philipp Jardas
  1. Socket.setSoTimeout()を使用して、ソケットに読み取りタイムアウトを設定する必要があります。これにより、指定された読み取りタイムアウトが経過した場合、読み取りメソッドはSocketTimeoutExceptionをスローします。 NB読み取りタイムアウトは、ストリームではなく、Socket.setSoTimeout().を介して基になるSocket,に設定されます。

  2. TCPには書き込みタイムアウトのようなものはありません。

11
user207421

この答えは 質問Timerを使用して接続を閉じる興味深い方法を説明しています。これが読み取りの途中で機能するかどうかは100%わかりませんが、一見の価値があります。

その答えからコピー:

TimerTask ft = new TimerTask(){
   public void run(){
     if (!isFinished){
       socket.close();
     }
   }
};

(new Timer()).schedule(ft, timeout);

isFinishedboolean変数である必要があり、ストリームからの読み取りが完了したらtrueに設定する必要があります。

4
tskuzzy