Как установить тайм-аут в 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, когда вы закончите чтение из потока.