Как установить тайм-аут в BufferedReader и PrintWriter в Java 1.4?
Как установить тайм-аут в 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));
}
}
Вне области действия этого кода я установил тайм-аут сокета в 1000 мс, который работает по назначению, ожидая начального соединения. Но программа блокирует в (str = br.readLine()). Если клиент зависает или падает, он никогда не прекращает блокировку, если я не завершаю процесс (который даже тогда не всегда работает).
Клиентский код, о котором идет речь, очень похож на этот и блокирует аналогичным образом.
Ответы
Ответ 1
Так как вызов 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
Вы можете использовать SimpleTimeLimiter из библиотеки Google Guava.
Пример кода (в 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
}
Ответ 3
В TCP нет такой вещи, как тайм-аут записи. Таймауты чтения устанавливаются не в потоке, а в базовом Socket,
через Socket.setSoTimeout().
Ответ 4
Ответ в этом question описывает интересный метод с использованием Timer
, чтобы закрыть соединение. Я не уверен на 100%, если это работает в середине чтения, но это стоит того.
Скопировано из этого ответа:
TimerTask ft = new TimerTask(){
public void run(){
if (!isFinished){
socket.close();
}
}
};
(new Timer()).schedule(ft, timeout);
isFinished
должна быть переменной boolean
, которая должна быть установлена на true
, когда вы закончите чтение из потока.