Как распознать 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 ответа
- Вы должны использовать существующие библиотеки для HTTP. Смотрите здесь.
- Ваш код работает как положено. Сервер не закрывает соединение, и
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
как предлагает Хачик, выполняет свою работу (поскольку закрытие соединения помогает определить конец ввода), но производительность ухудшается, потому что для каждого запроса вы запускаете новое соединение.
Конечно, это зависит от того, что вы пытаетесь сделать (если вам это важно или нет)