Почему конец входного потока никогда не достигается с помощью сокетов Java? - PullRequest
3 голосов
/ 11 февраля 2009

Я пишу простой прокси на Java. У меня проблемы с чтением всего данного запроса в байтовый массив. В частности, в следующем цикле вызов «чтения» блокируется, даже если клиент отправил все данные, которые он будет отправлять (то есть конец потока никогда не достигается). Так как я не могу быть уверен, что пришло время начинать писать вывод, пока я не прочитал весь ввод, это вызывает некоторые проблемы. Если я прерву соединение с сервером, конец потока, наконец, будет достигнут, и все пройдет без проблем (все данные с клиента, в данном случае Firefox, запрашивающий www.google.com, были прочитаны сервером и он может обработать его по мере необходимости, хотя, очевидно, он не может ничего отправить обратно клиенту).

public static void copyStream(InputStream is, OutputStream os) throws IOException
{
    int read = 0;
    byte[] buffer = new byte[BUFFER_SIZE];
    while((read = is.read(buffer, 0, BUFFER_SIZE)) != -1)
    {
      os.write(buffer, 0, read);
    }
    return;
}

InputStream поступает из клиентского сокета (getInputStream (), затем буферизируется) напрямую; OutputStream является ByteArrayOutputStream.

Что я делаю не так?

Ответы [ 3 ]

4 голосов
/ 11 февраля 2009

Обычно в HTTP заголовок Content-Length указывает, сколько данных вы должны прочитать из потока. В основном это говорит вам, сколько байтов следует за двойной новой строкой (фактически double- \r\n), которая указывает конец заголовков HTTP. См. W3C для получения дополнительной информации ...

Если заголовок Content-Length не отправлен, вы можете попытаться прервать чтение по истечении определенного промежутка времени, когда данные не передаются по соединению, хотя это определенно не является предпочтительным.

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

1 голос
/ 11 февраля 2009

Имейте в виду, что не все соединения будут иметь заголовок Content-Length; некоторые могут использовать Transfer-Encoding: chunked, где длина содержимого закодирована и включена как часть тела.

1 голос
/ 11 февраля 2009

HTTP 1.1, поддерживаемый всеми современными браузерами, имеет функцию «keep-alive» или «постоянные соединения», в которой клиентам по умолчанию разрешено повторно использовать соединение HTTP 1.1 с сервером для нескольких запросов (см. http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html). Поэтому, если вы указываете FF на http://www.google.com,, соединение с www.google.com:80 будет оставаться открытым некоторое время, даже если первый запрос был выполнен. Таким образом, вы не можете знать, были ли все данные отправлены без базового понимания протокола HTTP вашим приложением. Вы можете каким-то образом обойти это, используя тайм-аут в соединении, надеясь, что клиент не застрял где-то, и это молчание фактически означает конец блока данных. Другим способом было бы переписать заголовки ответов сервера, объявить прокси-сервер как совместимый с HTTP 1.0, а не как 1.1, запретив клиенту использовать постоянные соединения.

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