Как я должен читать с буферизованного читателя? - PullRequest
2 голосов
/ 23 марта 2010

У меня есть следующий пример чтения из буферизованного читателя:

while ((inputLine = input.readLine()) != null) {
   System.out.println("I got a message from a client: " + inputLine);
}

Код в цикле println будет выполняться всякий раз, когда что-то появляется в буферизированном считывателе (в данном случае input). В моем случае, если клиентское приложение записывает что-то в сокет, код в цикле (в серверном приложении) будет выполнен.

Но я не понимаю, как это работает. inputLine = input.readLine() ждет, пока что-то не появится в буферизированном считывателе, и когда что-то появится там, оно вернет true и код в цикле будет выполнен. Но когда null можно вернуть.

Есть еще один вопрос. Приведенный выше код был взят из метода, который throws Exception, и я использую этот код в методе выполнения Thread. И когда я пытаюсь поставить throws Exception перед run, компилятор жалуется: переопределенный метод не вызывает исключение. Без throws exception у меня есть еще одна жалоба от компилятора: незарегистрированное исключение. Итак, что я могу сделать?

Ответы [ 9 ]

5 голосов
/ 23 марта 2010

Когда сокет на другом конце закрыт, читатель должен вернуть пустую строку. Это условие, которое вы ищете. Чтобы обработать исключение, поместите цикл чтения в блок try / catch.

 try {
   while ((inputLine = input.readLine()) != null) {
     System.out.println("I got a message from a client: " + inputLine);
   }
 }
 catch (IOException e) {
   System.err.println("Error: " + e);
 }

Вы можете найти этот учебник по чтению / записи из / в сокет в Java, полезным.

3 голосов
/ 23 марта 2010

По первому вопросу:

Но я не понимаю, как это работает. inputLine = input.readLine () ждет, пока что-то не появится в буферизованном считывателе, и когда что-то там появится, оно вернет true и код в цикле будет выполнен. Но когда нуль можно вернуть.

BufferedReader.readLine() не возвращает true при успехе. Возвращает строку, содержащую прочитанную строку. Если достигнут конец потока, возвращается null.

Ваш второй вопрос:

Приведенный выше код был взят из метода, который выбрасывает Exception, и я использую этот код в методе выполнения Thread. И когда я пытаюсь поставить throws Exception перед запуском, компилятор жалуется: переопределенный метод не выдает исключение. Без исключения бросков у меня есть другая жалоба от компилятора: незарегистрированное исключение. Итак, что я могу сделать?

Вы должны заключить код в блок try / catch . Если вы не хотите обрабатывать перехваченное исключение, просто оставьте эту часть пустой (не рекомендуется)

try {
    while ((inputLine = input.readLine()) != null) {
        System.out.println("I got a message from a client: " + inputLine);
    }
} catch (Exception e) {
    //handle exception
}
1 голос
/ 23 марта 2010

Читатель readLine () вернет строковое значение, когда что-то прочитано, пустую строку, когда еще ничего нет, и ноль, когда соединение закрыто.

Я бы порекомендовал обернуть try / catch вокруг вашего блока кода с помощью функции IO и соответствующим образом обработать ошибки.

0 голосов
/ 23 марта 2010

Вы получили несколько хороших ответов. Просто поймайте исключение и разберитесь с ним локально. Если вам нужно передать это другому коду, но вы не можете, так как метод run() не допускает никаких проверочных исключений, вы можете заключить исключение в RuntimeException некоторого вида. Если метод run выполняется непосредственно в потоке (так как это, вероятно, Runnable), вам следует позаботиться о повторном вызове упакованного исключения.

Что касается результата из readLine(), он вернет null, когда больше нечего читать. В случае сокета это происходит, когда другая сторона аккуратно закрывает сокет (любое внезапное завершение или нечистое закрытие обычно приводит к исключению в вашем коде, так как ОС будет отправлять другой тип уведомления о закрытии сокета).

У меня есть одно слово предостережения, так как вы заключаете сокет в java.io.BufferedReader. Вы должны быть очень осторожны при использовании этого в любом виде производственного кода.

Опасность заключается в том, что BufferedReader плохо справляется с исключениями в разгар чтения. Это особенно важно, если вы включили тайм-аут в сокете, чтобы код автоматически получал периодические исключения из операционной системы. Тайм-аут (или другое исключение) может наступить во время заполнения буфера внутри считывателя. Если вы попытаетесь повторно использовать объект после исключения, он будет игнорировать любое предыдущее содержимое в буфере. Пакеты, которые были получены ранее, молча теряются, и нет способа извлечь эти байты.

Обратите внимание, что существуют другие виды исключений сокетов, которые не означают, что сокет был потерян. Например, посмотрите на определение java.io.InterruptedIOException. У него есть открытая переменная, которая сообщает количество байтов, успешно переданных в последнем запросе ввода-вывода (чтение или запись). Это означает, что операция ввода-вывода может быть выполнена снова для извлечения или отправки оставшихся байтов для пакета.

Если после какого-либо исключения ваш план заключается в немедленном закрытии считывателя и сокета, метод будет работать правильно.

Правильный способ чтения из сокета - это использовать поток сокета напрямую, использовать NIO (ByteBuffers и т. Д.) Или использовать хорошо написанную сетевую библиотеку с хорошими абстракциями над этими классами более низкого уровня (доступно несколько открытых источников) .

0 голосов
/ 23 марта 2010
while ((inputLine = input.readLine()) != null) {

Посмотрите на каждую часть выражения:

input.readLine()

Возвращает строку, которая будет нулевой, если достигнут конец потока (или выдается исключение при ошибке).

inputLine = input.readLine()

Назначает эту строку для inputLine

((inputLine = input.readLine()) != null)

Проверяет, что назначенная строка не является нулевой (конец потока).

0 голосов
/ 23 марта 2010

Если это не домашняя работа, вы можете посмотреть на Apache Commons IOUtils .

Предполагается, что вы не создаете BufferedReader, а просто остановитесь на InputStream:

String results = IOUtils.toString(inputStream);
System.out.println(results);
0 голосов
/ 23 марта 2010

null возвращается при достижении «EOF (конец файла)». Поскольку это чтение из сетевого сокета, конец файла создается при отключении сокета (либо сервером, либо клиентом), но вы, скорее всего, получите исключение до того, как увидите EOF.

0 голосов
/ 23 марта 2010

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

Нет, он возвращает значение выражения (inputLine = input.readLine ()), самого inputLine. InputLine сравнивается с нулем.

0 голосов
/ 23 марта 2010

input считыватель подключен к разъему, который является прослушивателем, то есть продолжает прослушивать входящие сообщения.

Что касается вашего второго вопроса, вы должны поместить в метод блок try / catch, перехватить исключение и обработать его. Не перекидывайте его.

...