Подтвердить что ты не робот

Как определить конец InputStream в java

Я пытаюсь читать байты с сервера с помощью программы Socket, то есть я использую InputStream для чтения байтов. Если я передаю размер длины, я могу прочитать байты, но я не уверен, что может быть длиной. Поэтому я не могу инициализировать массив байтов.

Также я пробовал while (in.read() != -1), я наблюдал, что он работает отлично, когда данные отправляются, но следующая строка после того, как цикл не является исполняемым, я чувствую, что он все еще ищет данные в потоке, но данных нет. Если я закрою соединение с Сервером, то мой клиент выполнит следующую строку, следующую в цикле.

Я не уверен, где я ошибаюсь?

this.in = socket.getInputStream();

int dataInt = this.in.read();

while(dataInt != -1){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}

System.out.print("End Of loop");

Я получаю вывод как: -

,1--0,2--62,3--96,4--131,5--142,6--1,7--133,8--2,9--16,10--48,11--56,12--1,13--0,14--14,15--128,16--0,17--0,18--0,19--48,20--0,21--0,22--0,23--0,24--0,25--1,26--0,27--0,28--38,29--114,30--23,31--20,32--70,33--3,34--20,35--1,36--133,37--48,38--51,39--49,40--52,41--49,42--55,43--49,44--52,45--52,46--54,47--55,48--50,49--51,50--52,51--48,52--53,53--56,54--51,55--48,56--48,57--57,58--57,59--57,60--57,61--57,62--57,63--57,64--56

Но нет вывода для: - Конец цикла

Укажите, как закрыть цикл?

Ждем вашего ответа. Спасибо всем заблаговременно.

4b9b3361

Ответ 1

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

Не понятно, разрабатываете ли вы клиентский/серверный протокол или просто пытаетесь его реализовать, но обычно есть три общих способа обнаружения конца сообщения:

  • Закрытие соединения в конце сообщения
  • Установка длины сообщения перед самими данными
  • Использование разделителя; какое-то значение, которое никогда не будет происходить в нормальных данных (или всегда будет сбежать каким-то образом)

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

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

Ответ 2

Я думаю, что вы действительно ответили на свой вопрос.

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

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

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


Теперь, если вы не хотите закрыть конец сервера сейчас, потому что позже вы хотите отправить больше информации в сокет, вам придется изменить протокол приложения, чтобы использовать какой-то механизм кадрирования. Например, сервер может отправить фрейм (или запись или что-то еще), состоящее из количества байтов, за которым следует заданное количество байтов. Альтернативно, он может использовать выделенное значение байта или последовательность байтов, чтобы пометить конец кадра.

Ответ 3

Вы можете запустить этот пример.

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

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

ServerSocket ss = new ServerSocket(0);
Socket s = new Socket("localhost", ss.getLocalPort());
Socket s2 = ss.accept();

final OutputStream out = s.getOutputStream();
out.write("Hello World!".getBytes());
out.close();

final InputStream in = s2.getInputStream();
for (int b = 0; ((b = in.read()) >= 0);) {
    System.out.println(b + " " + (char) b);
}
System.out.println("End of stream.");
s.close();
s2.close();
ss.close();

печатает

72 H
101 e
108 l
108 l
111 o
32  
87 W
111 o
114 r
108 l
100 d
33 !
End of stream.

Ответ 4

У меня была аналогичная проблема, когда in.read() просто зависает в конце данных, а не возвращает -1.

Если у вас нет контроля над кодом сервера, есть ли надежный маркер, который вы можете обнаружить в возвращаемых данных (например, "") и использовать это для завершения цикла чтения?

В противном случае рассмотрим использование socket.setSoTimeout(rationalValue), поэтому по крайней мере ваше приложение не будет постоянно вешать...

Ответ 5

В случае -1 он не заканчивает цикл. Положите 65535 в состояние, и я на 99% уверен, что он остановит цикл.

while(dataInt != 65535){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}

Ответ 6

Вы можете безопасно закрыть поток после цикла while. dataInt, равный -1, означает, что от него больше ничего не читать.

http://download.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html#read()

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

Ответ 7

У меня также была проблема, что я не вышел из цикла. Мое решение выглядело примерно так:

while (in.ready()){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}