Как установить время ожидания для BufferedReader и PrintWriter в Java 1.4? - PullRequest
14 голосов
/ 22 июля 2011

Как установить время ожидания для 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 ()). Если клиент зависает или аварийно завершает работу, он никогда не прекращает блокировку, если я не завершу процесс (который даже тогда не всегда работает).

Код клиента очень похож на этот и блокируется аналогичным образом.

Ответы [ 4 ]

16 голосов
/ 24 июля 2015

Вы можете использовать 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
}
11 голосов
/ 23 июля 2011
  1. Вам необходимо установить тайм-аут чтения для сокета с помощью Socket.setSoTimeout(). Это приведет к тому, что любой метод чтения выдаст SocketTimeoutException, если указанный тайм-аут чтения истечет. NB Время ожидания чтения устанавливается не в потоке, а в базовом Socket, через Socket.setSoTimeout().

  2. В TCP не существует такой вещи, как тайм-аут записи.

4 голосов
/ 22 июля 2011

Ответ на этот вопрос описывает интересный метод с использованием Timer для закрытия соединения. Я не уверен на 100%, работает ли это в середине чтения, но оно того стоит.

Скопировано из этого ответа:

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

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

isFinished должна быть boolean переменной, которая должна быть установлена ​​на true, когда вы закончите чтение из потока.

2 голосов
/ 22 июля 2011

Поскольку вызов socket.close (), по-видимому, не прерывал блок в br.readLine (), я сделал небольшой обходной путь.При отключении клиента от сервера я просто отправляю через строку «пока» и приказываю серверу закрыть соединение с сокетом при получении этой команды.

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));
}
...