基于 boost::asio 的慢速 http 客户端 - (分块传输)

2023-11-29

我正在使用以下代码(取自 boost 教程)从服务器获取 json 字符串。

问题是它需要一些时间来执行,即超过 2 秒才能完成,并且客户端和服务器都在本地主机上。如果我删除程序的最后两行,即此时:

while (boost::asio::read(套接字,响应, boost::asio::transfer_at_least(1),错误))

程序执行速度极快。可能是什么问题?

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

        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/")
        {
          std::cout << "Invalid response\n";
          return 1;
        }
        if (status_code != 200)
        {
          std::cout << "Response returned with status code " << status_code << "\n";
          return 1;
        }


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

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


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

        // Read until EOF, writing data to output as we go.
        boost::system::error_code error;
        while (boost::asio::read(socket, response,
              boost::asio::transfer_at_least(1), error))
          std::cout << &response;
        if (error != boost::asio::error::eof)
          throw boost::system::system_error(error);

tcpdump 显示来自服务器的一些数据

HTTP/1.1 200 OK
Connection: close
Content-Length: 42
Server: C/1.1
Date: Thu, 24 Nov 2016 07:47:27 GMT

{"Out":[1],"In":[1,2,3,4,5,6]}

从评论中的讨论可以看出,主要问题是读取分块数据。对于 HTTP 块编码数据,大小在块数据开始之前以十六进制为前缀。因此,必须读取该块的内容长度的大小。

      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 << "Version : " << 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;
      }

      bool chunk_size_present = false;
      std::string chunk_siz_str;

      // Ignore the remaining additional '\r\n' after the header
      std::getline(response_stream, header);

      // Read the Chunk size
      asio::read_until(socket, response, "\r\n");
      std::getline(response_stream, chunk_siz_str);
      std::cout << "CS : " << chunk_siz_str << std::endl;
      size_t chunk_size = (int)strtol(chunk_siz_str.c_str(), nullptr, 16);


      // Now how many bytes yet to read from the socket ?
      // response might have some additional data still with it
      // after the last `read_until`
      auto chunk_bytes_to_read = chunk_size - response.size();

      std::cout << "Chunk Length = " << chunk_size << std::endl;
      std::cout << "Additional bytes to read: " << response_stream.gcount() << std::endl;

      std::error_code error;
      size_t n = asio::read(socket, response, asio::transfer_exactly(chunk_bytes_to_read), error);

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

      std::ostringstream ostringstream_content;
      ostringstream_content << &response;

      auto str_response = ostringstream_content.str();
      std::cout << str_response << std::endl;

理解起来有点棘手的部分是asio::read_until保证它按照提供的模式读取数据,但它也可以将更多数据读取到缓冲区中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于 boost::asio 的慢速 http 客户端 - (分块传输) 的相关文章

随机推荐

  • 无法打开流:HTTP 包装器不支持可写连接

    我已将本地主机文件上传到我的网站 但它向我显示此错误 2 file put contents WebsiteURL cache lang FileName php function file put contents failed to o
  • PHP合并数组

    我一直在尝试 未成功 将多个数组的输出合并到一个数组中 我尝试过的一个例子是 data1 array cat goat data2 array dog cow print r array merge data1 data2 这工作得很好 但
  • 如何将 Unicode 字符作为 JSP/Servlet request.getParameter 传递?

    经过多次尝试和错误 我仍然无法找出问题所在 JSP Servlet 和数据库都设置为接受 UTF 8 编码 但即使如此 每当我对任何具有两字节字符 如破折号 的内容使用 request getParameter 时 它们都会被打乱为损坏的字
  • 有关内存映射接口的进一步问题

    我处理内存映射设备的 C 代码仍然存在一些问题 目前 我将写入的寄存器的地址空间声明为易失性 指针 我向它们写入数据 如下所示 volatile unsigned int wr register int 0x40000000 volatil
  • 如何在 iOS 上调用 Rootviewcontroller

    在我的 iOS 应用程序启动中检查用户是注册用户还是新用户 如 facebook 和 Skype 如果用户未注册 我正在导航应用程序以向我的应用程序委托注册屏幕 if user register RegisterViewController
  • Jquery Ajax POST 中出现 400 bad request 错误

    我正在尝试使用 Jquery 发送 Ajax POST 请求 但遇到 400 bad request 错误 这是我的代码 ajax type POST url http localhost 8080 project server rest
  • 在Lua中生成均匀随机数

    我正在用 Lua 编写马尔可夫链 其中一个要素要求我统一生成随机数 这是一个简化的例子来说明我的问题 example function x local r math random 1 10 print r return x r end ex
  • Servlet - 关闭连接但不关闭方法

    我必须实现将发送的服务 servlet 2 5 或 3 204在每个连接上编写代码但不关闭线程 我需要对收到的数据做一些事情 比如打开新连接 可以关闭连接但不能结束方法吗 或者在连接关闭时启动另一个方法 规范中尚不清楚 但它似乎可以在 To
  • 如何在服务器端获取客户端屏幕分辨率宽度/高度

    我可以使用客户端脚本 javascript 获取客户端屏幕分辨率 但我不想那样做 我也尝试过Request Browser ScreenPixelsWidth 但它总是返回固定宽度680 任何想法 客户端屏幕分辨率等信息是never在 HT
  • RDPSession ConnectToClient 意外终止

    我已经成功创建了一个桌面共享解决方案 其中 RDPViewer 连接到 RDPSession 这一切都很顺利 然而 现在我正在尝试相反的方法 使用 RDPViewer 的 StartReverseConnectListener 方法和 RD
  • 复制具有 unicode 名称的文件

    这应该是一个简单的脚本 import shutil files os listdir C for efile in files shutil copy efile D 它工作得很好 直到我在电脑上尝试使用 unicode 字符命名的文件 p
  • 具有地理位置策略的 AWS Cloudfront 与 Route53

    我们可以将CloudFront与Geolocation策略一起使用吗 或者CloudFront内部是否具有此功能并且可以单独使用来满足 或者 Route53 是一个正确的选择 同时需要为全球网站提供来自最近地理位置的请求以改善客户体验 另外
  • 为什么PHP不能创建777权限的目录?

    我正在尝试使用 PHP 和以下命令在我的服务器上创建一个目录 mkdir test 0777 但它并没有给出完整的权限 只有这些 rwxr xr x 该模式根据您当前的情况进行修改umask 即022在这种情况下 方式umask作品是一种减
  • Laravel 8:未定义方法“createToken”intelephense(1013)

    我对 PHP intelephense 方法有疑问创建令牌未定义 我不知道如何解决它 但是当我在邮递员中运行它时它就起作用了 我不知道为什么 vscode 不识别它 我还添加了使用 Laravel Passport HasApiTokens
  • HQL IN 运算符,枚举数组 ClassCastException

    这是我精简的类和枚举 class A Enumerated value EnumType STRING AType type enum AType X Y 如果我跑 query FROM A a WHERE a type type quer
  • Karate WebSocket 如何在一个会话中监听多个消息?

    对于我们的集成测试 我们有一个场景 我们想要监听由我们使用的环境预定义的一定数量的消息 我已经看到可以通过打开新连接来收听多个消息 但这并没有太大的灵活性 您是否阅读过文档 因为据我所知 如果您定义了 处理程序 函数 则可以对多个消息使用相
  • 在 R 中结合 grid_arrange_shared_legend() 和facet_wrap_labeller()

    我正在尝试结合grid arrange shared legend and facet wrap labeller 更具体地说 我想绘制一个包含两个 ggplot 图形的图形 每个图形都有多个面板 并且有一个共同的图例 我还想将部分刻面条标
  • 使用批处理文件并排合并 csv 文件[重复]

    这个问题在这里已经有答案了 我有一个非常基本的批处理命令来将 csv 文件合并在一起 但是我需要将它们合并 以便各列并排而不是继续 每个文件上的记录数量始终相同 这是我到目前为止的基本代码 COPY File1 csv File2 csv
  • 尝试使用 XML 配置关闭一个 URL 的安全性

    我检查了几个博客 doc stackoverflow 论坛条目 但我仍然不知道我做错了什么 我想向任何人授予对 URL 的访问权限 这permitAll不起作用 因为我有自定义过滤器 所以我想创建一个单独的http元素并使用security
  • 基于 boost::asio 的慢速 http 客户端 - (分块传输)

    我正在使用以下代码 取自 boost 教程 从服务器获取 json 字符串 问题是它需要一些时间来执行 即超过 2 秒才能完成 并且客户端和服务器都在本地主机上 如果我删除程序的最后两行 即此时 while boost asio read