Входной поток сокета зависает при окончательном чтении. Лучший способ справиться с этим?

Я немного зациклен на том, как избежать того, чтобы мой сокет висел на чтении. Здесь мой код:

    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), как я могу обойти это (то есть прекратить чтение, когда он зависает).

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

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

Ответ 3

Я не эксперт по 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());
        }
    }

Ответ 4

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

Ответ 5

Try:

while ((result = in.read()) != null) {

Ответ 6

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

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

a) Поиск определенной строки, которая, как я знаю, сигнализирует о завершении      полезная информация из потока.
б) Или начать новую тему, которая      убивает процесс на другом конце сокета, в этом случае для      me 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++;
        }