ソケット接続を使用して作成された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())でブロックします。クライアントがハングまたはクラッシュした場合、プロセスを終了しない限り、ブロックが停止することはありません(それでも常に機能するとは限りません)。
問題のクライアントコードはこれと非常によく似ており、同様の方法でブロックしています。
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));
}
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
}
Socket.setSoTimeout()
を使用して、ソケットに読み取りタイムアウトを設定する必要があります。これにより、指定された読み取りタイムアウトが経過した場合、読み取りメソッドはSocketTimeoutException
をスローします。 NB読み取りタイムアウトは、ストリームではなく、Socket.setSoTimeout().
を介して基になるSocket,
に設定されます。
TCPには書き込みタイムアウトのようなものはありません。
この答えは 質問Timer
を使用して接続を閉じる興味深い方法を説明しています。これが読み取りの途中で機能するかどうかは100%わかりませんが、一見の価値があります。
その答えからコピー:
TimerTask ft = new TimerTask(){
public void run(){
if (!isFinished){
socket.close();
}
}
};
(new Timer()).schedule(ft, timeout);
isFinished
はboolean
変数である必要があり、ストリームからの読み取りが完了したらtrue
に設定する必要があります。