BufferedReader никогда не готов (Socket-программирование на Java) - PullRequest
6 голосов
/ 19 мая 2011

У меня есть сокет, уже объявленный как сокет:

serverAddr = InetAddress.getByName(this.ip);
socket = new Socket(serverAddr, port);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

однако следующее не работает. in.ready() всегда возвращает false, и в случае удаления программа остановится на String message = in.readLine();

private void receive() {
        try {
            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            System.out.println(isr.getEncoding());
            BufferedReader in = new BufferedReader(isr);
            if (in.ready()) {
                String message = in.readLine();
                if (message != null) {
                    if (listener != null) {
                        listener.receiveMessage(ip, message);
                    } else {
                        print("Client recieved: " + message);//
                    }
                }
            }
            in.close();
        } catch (Exception e) {
            print("Error with input stream: " + e);
            disconnect();
        }

    }

Как я могу решить это?

EDIT:

Вот так выглядит отправка в моем классе сервера: out.println (сообщение); out.flush (); Это происходит в цикле всякий раз, когда я помещаю что-то в сообщение. выход закрыт после этого цикла.

Ответы [ 4 ]

4 голосов
/ 19 мая 2011

Вы не должны использовать ready(), как это. javadoc говорит следующее:

"Возвращает: True, если гарантируется, что следующее чтение () не заблокирует ввод, в противном случае - false. Обратите внимание, что возвращение false не гарантирует, чтоследующее чтение заблокирует. "

Ваш код неявно предполагает, что ready() -> false означает, что следующий read заблокируется.На самом деле это означает, что следующий read может или не может блокировать .

Как говорит @EJP ... просто сделайте вызов read.


Что я могу сделать, чтобы предотвратить блокировку?Клиент не сможет отправлять что-либо, если он заблокирован

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

2 голосов
/ 19 мая 2011

Просто удалите тест in.ready ().Это не помогает тебе.readLine () будет блокировать, пока не будут доступны данные.Что еще вы планировали сделать, если данные еще не поступили?

1 голос
/ 19 мая 2011

Мне на ум приходят 3 вещи:

  • Вы повторно открываете входной поток при каждом receive вызове и заключаете его в BufferedReader.Это может прочитать более одной строки в буфер, и после завершения (закрытия) оставшиеся буферизованные байты больше не будут доступны для последующих receive вызовов
  • . Вы думали об использовании собственного потока длячтение сообщений с сервера?Там это не повредит, если оно заблокировано
  • У меня возникли некоторые проблемы при закрытии одной стороны сокета после записи данных и немедленном закрытии.Иногда не все данные были получены другой стороной, несмотря на вызовы flush() и close().Может быть, это также проблема в вашей ситуации

Редактировать:
Простое сохранение ссылки in вне метода receive не решит полностью вашу проблему.Вы должны использовать цикл while для чтения всех буферизованных сообщений и вызывать слушателя для всех, например:

if (in.ready()) {
    String message;
    while ((message = in.readLine()) != null) {
        // ...
    }
 }

Но следите за тем, чтобы последняя строка могла быть частично прочитанным сообщением (например, сообщения 3 и 1/2).были забуферены).Если это проблема, вы можете прочитать сообщения char-by-char, чтобы определить, когда заканчивается строка, и использовать PushbackReader для возврата неполных сообщений.

0 голосов
/ 19 мая 2011

Возможно, вам придется позвонить out.flush(), чтобы сбросить что-либо в BufferedWriter

...