c++ - 尝试将 streambuf 响应作为字符串获取时 boost::asio 问题

标签 c++ c++11 boost boost-asio

我使用 boost::asio 中的基本示例连接到一个 enpoint 并返回一个 json 响应。这是代码

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

// Check that response is OK. 
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
        LOG_ERROR << "invalid response";
        return -1; 
}

resp_status_code_ = status_code;

resp_status_code_ = status_code;

if (status_code != 200) {
        LOG_ERROR << "response did not returned 200 but " << status_code;
        return -1; 
}

//read until the response headers termination 
boost::asio::read_until(socket_, response, "\r\n\r\n");

//read the headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r") {
         ;
}

std::ostringstream ostringstream_content;
if (response.size() > 0)
        ostringstream_content << &response;

boost::system::error_code error;

boost::system::error_code error;
while (true) {
        size_t n = boost::asio::read(socket_, response, boost::asio::transfer_at_least(1), error);

        if (!error)
        {
                if (n)
                        ostringstream_content << &response;
        }

        if (error == boost::asio::error::eof)
                break;

        if (error)
                return -1; //throw boost::system::system_error(error);
}

str_response_ = ostringstream_content.str();

但是当字符串返回时我正在阅读这个

  1 [5a0
  2 {"a_token":"eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Nzk5Mjk2NjcsIn...030"}
  3 0
  4 
  5 ]

[ 和 ] 是我代码中的标记,用于相应地调试数据的开始和结束。我有不止一行,第一行有 3 个有问题的字符,即 5a0,第二行中的 json 字符串是正确的,然后 一个零和一个空行。我怎样才能得到准确的 json 字符串?

最佳答案

我修改了您的示例,它对我来说效果很好。请注意,我为阅读回复设置了一些快捷方式。我正在一次读取状态行和标题而不是单独读取(纯粹是出于懒惰)

#include <asio.hpp>
#include <iostream>
#include <sstream>
#include <istream>

int main(int argc, const char * argv[]) {

    static asio::io_service ios;
    asio::ip::tcp::endpoint
    endpoint(asio::ip::address::from_string("127.0.0.1"), 8000);
    asio::generic::stream_protocol::socket socket{ios};
    socket.connect(endpoint);

    std::string req = "GET /api\n\r\n\r\n";
    std::error_code ec;
    socket.write_some(asio::buffer(req, req.size()), ec);
    std::cout << "Request sent" << std::endl;

    if (ec == asio::error::eof) {
      std::cerr << "Premature termination\n";
      return 1;
    }
    //while (true) {
    {
          asio::streambuf response;
          // Get till all the headers
          asio::read_until(socket, response, "\r\n\r\n");

          // Check that response is OK. 
          std::istream response_stream(&response);
          std::string http_version;
          response_stream >> http_version;
          std::cout << "V : " << http_version << std::endl;

          unsigned int status_code;
          response_stream >> status_code;

          std::string status_message;
          std::getline(response_stream, status_message);

          if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
            std::cerr << "invalid response";
            return -1; 
          }

          if (status_code != 200) {
            std::cerr << "response did not returned 200 but " << status_code;
            return -1; 
          }

          //read the headers.
          std::string header;
          while (std::getline(response_stream, header) && header != "\r") {
            std::cout << "H: " << header << std::endl;
          }

          std::ostringstream ostringstream_content;
          if (response.size() > 0) {
            ostringstream_content << &response;
          }

          std::error_code error;
          while (true) {
            size_t n = asio::read(socket, response, asio::transfer_at_least(1), error);
            if (!error) {
                if (n) {
                  ostringstream_content << &response;
                }
            } 

            if (error == asio::error::eof) {
                break;
            }
            if (error) {
                return -1; //throw boost::system::system_error(error);
            }
          }
          auto str_response = ostringstream_content.str();
          std::cout << str_response << std::endl;
    }

    //}

    return 0;
}

还有我用于测试的 python 服务器:

Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket as s
>>> sd = s.socket(s.AF_INET, s.SOCK_STREAM)
>>> sd.bind(("127.0.0.1", 8000))
>>> sd.listen(1)
>>> c, a = sd.accept()
>>> resp = "HTTP/1.1 200 OK\nDate: Fri, 31 Dec 1999 23:59:59 GMT\nContent-Type: text/plain\nTransfer-Encoding: chunked\n\r\n\r\n{\"token\":\"eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Nzk5Mjk2NjcsIn...030\"}"
>>> c.send(resp)
173
>>> exit()

ASIO 输出:

MacBook-Pro:asio_test amuralid$ ./json_read_so
Request sent
V : HTTP/1.1
H: Date: Fri, 31 Dec 1999 23:59:59 GMT
H: Content-Type: text/plain
H: Transfer-Encoding: chunked

{"token":"eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Nzk5Mjk2NjcsIn...030"}

关于c++ - 尝试将 streambuf 响应作为字符串获取时 boost::asio 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40771421/

相关文章:

c++ - 使用 Dart 端口将 Float32x4 数组从 native 主机发送到 Dart 虚拟机

c++ - 对 mersenne_twister 的调用比预期的要多

C++:如何创建一个临时对象,包含一个指针 - const 或非常量,具体取决于上下文?

c++ - std::string 引用、std::regex 和 boost::filesystem 的基本概念

c++ - 如何为 boost::tokenizer 实现 tokenizer.rbegin() 和 rend()?

c++ - VS中的VTK和QT调试

c++ - C++中的点星号运算符

c++ - boost 动态数组的序列化

python - boost Python : stop interpreter

c++ - 如何在不格式化的情况下写入 std::ostream?