Сокеты: блоки BufferedReader readLine()

Я использую метод BufferedReader.readLine() для чтения ответа с удаленного сервера (который написан на C, и у меня нет доступа к исходному коду).

BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while((line = br.readLine())!=null){
    [...]
}

Но он всегда блокируется на последней строке, пока не истечет время ожидания. Поэтому я использовал следующий код:

int b;
while(true){
   b = in.read;
   [...]
}

и я обнаружил, что последний прочитанный байт имеет целочисленное значение 13, что, я думаю, является возвратом каретки, верно?

Так почему же метод readLine блокируется? Как сервер обычно сигнализирует о достижении конца потока? Спасибо.


person neo    schedule 26.05.2011    source источник
comment
Не могли бы вы вставить свой неблокирующий код, который вы используете. Я смотрю, что можно сделать для неблокирующих входов   -  person Prakhar Agrawal    schedule 11.02.2017
comment
@PrakharAgrawal О чем ты говоришь? Здесь нет и не упоминается неблокирующий код.   -  person user207421    schedule 23.01.2020


Ответы (4)


В случае сетевого подключения поток завершается при закрытии сокета.

Таким образом, совершенно нормально, что readLine() блокируется до тех пор, пока не будет получен "конец строки" или пока вы не закроете соединение вручную. Когда ваш readLine() получает последний символ со значением «13», строка считывается, и цикл начинается снова, ожидая следующей строки.

Нет никакой разницы между «последней строкой» и другими строками.

Чтобы остановить цикл, вы должны где-то вручную закрыть соединение или дождаться тайм-аута. Но без дополнительной информации о вашем протоколе связи невозможно быть более точным в этом вопросе.

person krtek    schedule 26.05.2011
comment
Ты прав; код ожидает \r, а затем не забывает пропустить следующий перевод строки (если есть). - person Aaron Digulla; 26.05.2011

Это зависит от протокола. Если сервер не закроет поток, readLine будет блокироваться до тех пор, пока не будет получен правильный конец строки. Поэтому, если сервер никогда не отправляет правильный конец строки, вы заблокированы. Возможно, вам следует использовать более низкоуровневые методы и попытаться получить документацию по протоколу или перепроектировать ее.

person JB Nizet    schedule 26.05.2011

убедитесь, что код сервера имеет out.println() вместо out.print()

person MayureshG    schedule 23.10.2013

Вы можете расширить условие while, если не используете пустые строки:

while((line = br.readLine())!=null && line.length() > 0) {
   // ...
}
person Grzegorz Pawełczuk    schedule 03.01.2014
comment
да, правильная мысль. Еще одна вещь, которую вы можете сделать, это использовать специальную последовательность символов в конце сообщения. Объявление чего-то вроде «EOM» = \n\n, где «EOM» — это EndOfMessage - person BQuadra; 09.01.2014
comment
За исключением того, что readLine будет блокироваться до тех пор, пока не будет обнаружен конец строки или поток не будет закрыт. - person Keenan; 10.11.2017