HTTP-разделение заголовка ответа и не HTTP-данных - PullRequest
1 голос
/ 09 февраля 2012

Я просто пишу небольшое клиентское HTTP-приложение.Он просто отправляет запрос GET на IP-камеру, а затем получает снимок экрана в формате jpeg.

Теперь для реализации HTTP я использую Boost Asio.Итак, для первой попытки я в значительной степени ориентировался на пример sync_client Пример использования HTTP-клиента Boost Asio Sync .

Теперь в основном меня немного беспокоит разделение заголовков и данных.

Сначала я получаю первую строку ответа:

boost::asio::streambuf response;
boost::asio::read_until(*m_Socket, response, "\r\n");

std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;

 if (!response_stream || http_version.substr(0, 5) != "HTTP/")
 {
     std::cout << "Invalid response\n";
     return;
 }

uint32_t status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);  

 if (status_code != 200)    // 200 = status code OK
 {
     std::cout << "Response returned with status code " << status_code << "\n";
     return;
 }

Теперь, пока все здесь, мне все ясно. Я читаю до первой новой строки, а затем проверяю содержимое в моем буфере.

Теперь я пытаюсь прочитать вторую часть заголовка:

 boost::asio::read_until(*m_Socket, response, "\r\n\r\n");

 std::string header;
 while (std::getline(response_stream, header) && (header != "\r"))
 {
      std::cout << header << "\n";
 }
 std::cout << "\n";

Теперь к этому у меня есть несколько вопросов:

  1. ВремяЦикл ищет, пока не будет пустой строки (единственная строка, где \r стоит отдельно).Теперь, если я предполагаю, что новая строка определяется как \r, почему я использую \r\n\r\n в boost::asio::read_until?Я имею в виду, ожидал ли я того или другого, но оба?

  2. Если я вызову метод boost::asio::read_until с \r\r в качестве разделителя, он выдаст исключение End of File.Это противоречит тому, что ищет мой цикл while, поскольку он ищет \r\r (поскольку он просматривает строку за строкой, а каждая строка закрывается с \r)

Так что, как вы можете видеть, я очень волнуюсь, как разделить вещи внутри моего заголовка.Это становится еще хуже, потому что вызов boost::asio::read_until всегда читает дальше, чем разделитель (это на самом деле нормально, так как это упомянуто в документации), но все равно он всегда имеет один и тот же след данных (из фактического jpeg), сследующая длина:

Может быть, кто-то мог бы просветить меня?

Ответы [ 2 ]

3 голосов
/ 09 февраля 2012

«\ r» - символ возврата каретки (CR), а «\ n» - символ перевода строки (LF).Строки сообщений HTTP заканчиваются на «\ r \ n» (CRLF).

Из «Руководства по HTTP»:

Стоит отметить, что в то время как спецификация HTTP длязавершающие строки - CRLF, надежное приложение также должно принимать только символ перевода строки.Некоторые старые или неработающие HTTP-приложения не всегда отправляют как возврат каретки, так и перевод строки.

Кажется, что вас отталкивает то, что некоторые функции ввода-вывода строки (в данном случае std :: getline()) автоматически удаляет завершающий символ '\ n', так что вы видите только предыдущий '\ r'.Я думаю, что вы должны делать, ищет пустую строку (а не строку только с '\ r').И строка, которая является только '\ r', должна рассматриваться как пустая строка.

2 голосов
/ 09 февраля 2012

Разделитель "\r\n\r\n" используется для отделения заголовков от фактического ответа сервера (то есть изображения JPEG, которое вы извлекаете). Вот почему вы используете это; Заголовки разделены "\r\n".

Вы должны читать до "\r\n\r\n". Все, что приходит потом, это изображение JPEG. Обратите внимание, что вы можете угадать длину файла, проверив заголовок Content-Length, или просто читайте, пока сервер не закроет сокет.

...