Входной поток сокетов зависает при окончательном чтении.Лучший способ справиться с этим? - PullRequest
11 голосов
/ 03 февраля 2011

Я немного озадачен тем, как избежать зависания сокета при чтении.Вот мой код:

    Socket socket = new Socket("someMachine", 16003);
    OutputStream outputStream = socket.getOutputStream();
    InputStream inputStream = socket.getInputStream();
    try {
        outputStream.write(messageBuffer.toByteArray());
        outputStream.flush();
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
        StringBuffer response = new StringBuffer();
        int result;
        while ((result = in.read()) != -1) {
            response.append(Character.toChars(result));
            System.out.println(result);
        }
        System.out.println("Done!");  //never gets printed
     } catch (...) {}

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

(Lots of data above this point)
57
10
37
37
69
79
70
10

Этопотом висит.Итак, мои вопросы:

1) Я неправильно закодировал это или есть проблема с ответом сервера?

2) Если есть проблема с ответом сервера (т.е. нет -1 возвращается), как я могу обойти это (например, чтобы остановить чтение, когда он зависает).

Любая помощь приветствуется!

Ответы [ 6 ]

12 голосов
/ 03 февраля 2011

Проблема с простой остановкой там, где чтение зависает, состоит в том, что это может произойти в 2 случаях:

1: на сервере больше нет данных для отправки

2: сервер отправил больше данных, но ваш клиент еще не получил их из-за перегрузки сети.

И вы действительно хотите остановить чтение только в первом случае, но вы хотите, чтобы чтение блокировалось во втором случае.

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

Если сервер заранее знает общий размер данных, просто начните с отправки общего количества байтов в передаче, а затем отправьте данные. Таким образом, клиент знает, когда он получил все данные.

(Или сервер может просто закрыть соединение, когда закончите. Таким образом, read должен потерпеть неудачу, но это будет работать, только если в будущем вам не нужно соединение)

5 голосов
/ 03 февраля 2011

Я думаю, вы получите -1 только тогда, когда сервер решит прекратить разговор, то есть закроет свой поток вывода или полностью закроет сокет. В противном случае поток остается открытым для потенциальных будущих поступающих данных.

2 голосов
/ 11 декабря 2012

У меня была точно такая же проблема. Я решил это, установив таймаут сразу после создания объекта сокета ... socket.setSoTimeout (10 * 1000);

2 голосов
/ 21 мая 2012

Я не эксперт по Android, но на Android это работает нормально:

    try {
        telnetClient = new Socket(server, port);
    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    if (telnetClient.isConnected()) {
        try {
            InputStream instr = telnetClient.getInputStream();
            int buffSize = telnetClient.getReceiveBufferSize();
            if (buffSize > 0) {
                byte[] buff = new byte[buffSize];
                int ret_read = instr.read(buff);
                screen.append(new String(buff, 0, ret_read));
            }
        } catch (IOException e) {
            screen.append("Exception while reading socket:" + e.getMessage());
        }
    }
0 голосов
/ 09 октября 2017

Я нашел эту проблему довольно грозной.Я пытался выполнить пакетную команду Windows из Java, и процесс зависает каждый раз, пытаясь прочитать входные данные из выполняемой команды.

Я мог только исправить это неуверенно.

a) Поиск конкретной строки, которая, как я знаю, будет сигнализировать о конце полезной информации из потока.
b) Или запустить новый поток, который убивает процесс на другом конце сокетав этом случае для меня IEDriverServer.exe после времени ожидания.

String[] cmdArray = {"cmd.exe","/c",cmd+ " 2>&1" };
    InputStream is = new ProcessBuilder(cmdArray).directory(f).start().getInputStream();

        error_buffer = new BufferedReader(new InputStreamReader(is));
        int lines=0;

        while((line=error_buffer.readLine())!=null){
            if(line.startsWith("[INFO] Final Memory: ")) {
                break;
            }

            log.debug("Reading cmd Stream "+line);
            buf.append(line);
            lines++;
        }
0 голосов
/ 03 февраля 2011

Попробуйте:

while ((result = in.read()) != null) {
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...