Как распознать EOF в сокетах Java?

Я хочу распознать конец потока данных в сокетах Java. Когда я запускаю приведенный ниже код, он просто зависает и продолжает работать (он зависает в значении 10).

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

String host = "example.com";
String path = "/";
Socket connection = new Socket(host, 80);

PrintWriter out = new PrintWriter(connection.getOutputStream());
  out.write("GET "+ path +" HTTP/1.1\r\nHost: "+ host +"\r\n\r\n");
out.flush();

int dataBuffer;
while ((dataBuffer = connection.getInputStream().read()) != -1)
  System.out.println(dataBuffer);

out.close();

Спасибо за любые подсказки.

2 ответа

Решение
  1. Вы должны использовать существующие библиотеки для HTTP. Смотрите здесь.
  2. Ваш код работает как положено. Сервер не закрывает соединение, и dataBuffer никогда не становится -1, Это происходит потому, что соединения по умолчанию поддерживаются в HTTP 1.1. Используйте HTTP 1.0 или положите Connection: close Заголовок в вашем запросе.

Например:

out.write("GET "+ path +" HTTP/1.1\r\nHost: "+ host +"\r\nConnection: close\r\n\r\n");
out.flush();

int dataBuffer;
while ((dataBuffer = connection.getInputStream().read()) != -1) 
   System.out.print((char)dataBuffer);

out.close();

На самом деле ваш код неверен.

В HTTP 1.0 каждое соединение закрывается, и в результате клиент может определить, когда ввод закончился.

В HTTP 1.1 с постоянными соединениями базовое TCP-соединение остается открытым, поэтому клиент может определить, когда ввод заканчивается одним из следующих двух способов:

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

2) Ответ отправлен Chunked-Encoding Это означает, что он состоит из фрагментов с префиксом размера каждого фрагмента. Клиент, использующий эту информацию, может создать ответ из чанков, полученных сервером.

Вы должны использовать HTTP-клиентскую библиотеку, поскольку реализация универсального HTTP-клиента не тривиальна (я бы даже сказал).

Чтобы быть конкретным в своем опубликованном коде, вы должны следовать одному из вышеуказанных подходов.

Кроме того, вы должны читать в строках, так как HTTP является протоколом с завершением строки.

Т.е. что-то вроде:

BufferedReader in =new BufferedReader(new InputStreamReader( Connection.getInputStream() ) );
String s=null;
while ( (s=in.readLine()) != null)  {
//Read HTTP header
     if (s.isEmpty()) break;//No more headers
   }
}

Отправив Connection: close как предлагает Хачик, выполняет свою работу (поскольку закрытие соединения помогает определить конец ввода), но производительность ухудшается, потому что для каждого запроса вы запускаете новое соединение.

Конечно, это зависит от того, что вы пытаетесь сделать (если вам это важно или нет)

Другие вопросы по тегам