BufferedReader не читает после пустой строки

Я пытаюсь понять, почему мой BufferedReader (чтение из InputStream) просто зависает и не читает после получения пустой строки.

Попытка прочитать запрос POST, который выглядит примерно так:

POST /test.php HTTP/1.0
Content-Length: 30
Content-Type: text/html;

postData=whatever&moreData...

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

while (true) {
    System.out.println(bufferedReader.readLine());
}

Код, используемый для получения потока:

bufferedReader = new BufferedReader(clientSocket.getInputStream());

Кто-нибудь знает, почему это происходит?

Спасибо


person cud_programmer    schedule 24.11.2012    source источник
comment
Пожалуйста, опубликуйте код, используемый для получения потока   -  person Aubin    schedule 24.11.2012
comment
Я ожидал, что bufferedReader = new BufferedReader(новый URL(http://...).openConnection()); Зачем использовать сокет для HTTP?   -  person Aubin    schedule 24.11.2012
comment
это часть простого сервера - поэтому нужны сокеты   -  person cud_programmer    schedule 24.11.2012
comment
сервер - я читаю отправленный запрос POST - поэтому пытаюсь прочитать отправленные данные (после пустой строки), но не могу их получить   -  person cud_programmer    schedule 24.11.2012
comment
Если это часть сервера, почему дескриптор сокета называется clientSocket? Означает ли это сокет, с помощью которого можно разговаривать с клиентом?   -  person seh    schedule 24.11.2012
comment
Пожалуйста, включите код, который вы используете для отправки данных от клиента.   -  person Perception    schedule 24.11.2012
comment
Он печатает пустую строку? Закрывает ли клиент свой конец сокета? В противном случае ваш InputStream не сообщит о конце строки, а если тело сообщения POST не завершается CR или LF, BufferedReader не вернет содержимое неполной строки.   -  person seh    schedule 24.11.2012


Ответы (1)


Метод POST не добавит символ новой строки в конце. Что вам нужно сделать, так это получить Content-Length и после последней пустой строки прочитать столько символов.

Пример

Предположим, у нас есть следующая HTML страница:

<html>
<head/>
<body>
    <form action="http://localhost:12345/test.php" method="POST">
        <input type="hidden" name="postData" value="whatever"/>
        <input type="hidden" name="postData2" value="whatever"/>
        <input type="submit" value="Go"/>
    </form>
</body>
</html>

Теперь запускаем очень простой сервер, который чем-то напоминает ваш код (в этом коде полно целых, но дело не в этом):

public class Main {
    public static void main(final String[] args) throws Exception {
        final ServerSocket serverSocket = new ServerSocket(12345);
        final Socket clientSocket = serverSocket.accept();
        final InputStreamReader reader = new InputStreamReader(clientSocket.getInputStream());
        final BufferedReader bufferedReader = new BufferedReader(reader);
        int contentLength = -1;
        while (true) {
            final String line = bufferedReader.readLine();
            System.out.println(line);

            final String contentLengthStr = "Content-Length: ";
            if (line.startsWith(contentLengthStr)) {
                contentLength = Integer.parseInt(line.substring(contentLengthStr.length()));
            }

            if (line.length() == 0) {
                break;
            }
        }

        // We should actually use InputStream here, but let's assume bytes map
        // to characters
        final char[] content = new char[contentLength];
        bufferedReader.read(content);
        System.out.println(new String(content));
    }
}

Когда мы загружаем страницу в нашем любимом браузере и нажимаем кнопку Go, мы должны отобразить содержимое тела POST в консоли.

person ShyJ    schedule 24.11.2012
comment
Я знаю, что это всего лишь пример кода, но, но, но... Пробел после двоеточия поля заголовка Content-Length не требуется в соответствии с RFC 2616 §4.2. Кроме того, для удобства будущих читателей, которые хотят изменить код вопреки нашему совету, заголовок Content-Length не обязан указывать границу тела сообщения. RFC 2616 §4.4 определяет четыре варианта: заголовок Content-Length, кодирование передачи по частям, тип мультимедиа multipart/byteranges или завершение соединения клиентом, указывающее EOF на сервер. ietf.org/rfc/rfc2616.txt - person seh; 24.11.2012
comment
@seh Ну, в принципе, я не хотел включать код для полноценного HTTP-сервера. Пример должен был проиллюстрировать, почему код OP не работает, и возможное решение в очень ограниченном случае. - person ShyJ; 24.11.2012
comment
Я понимаю; отсюда мое упоминание примера кода. @Aubin спросил, почему OP не использует здесь HttpURLConnection, и ответ был: [T] это часть простого сервера, поэтому нужны сокеты. Этого достаточно, чтобы я беспокоился о том, что он строит. - person seh; 24.11.2012
comment
в этом была проблема - я не использовал InputStream, читая массив символов/байтов. Спасибо! - person cud_programmer; 24.11.2012
comment
@seh то, что я дал, является лишь небольшой частью всего кода - я знал, что другие биты работают, поскольку я запускал на них тесты, проблема заключалась в том, чтобы просто извлечь эти опубликованные данные. Но теперь все в порядке :) - person cud_programmer; 24.11.2012
comment
не взорвется ли этот код, как только bufferedReader.readLine() станет нулевым ..? - person Amalgovinus; 24.06.2016
comment
if (line.length() == 0) Это совсем не то, что вам нужно. Строка нулевой длины вполне возможна, это не значит, что контента больше нет... - person Amalgovinus; 24.06.2016