Boost.asio 套接字 - 为什么没有可用字节

发布于 2024-12-16 12:32:12 字数 3210 浏览 0 评论 0原文

我刚开始使用 boost.asio,但我想设计一个简单的例程来从 URL 获取数据并将其保存到内存缓冲区。根据我发现的一个例子,我想出了以下内容:

//data_url.hpp

#include <boost/asio.hpp>
#include <string>
#include <vector>

struct data {
  data();
  boost::asio::io_service io_service;
  boost::asio::ip::tcp::resolver resolver;
  boost::asio::ip::tcp::socket socket;
  std::vector<char> buffer;
  std::string host;
  std::string path;
  std::string port;
};

void setup_url(std::string hst, 
               std::string pth, 
               std::string prt = "80");

std::vector<char> & get_data_from_url();

void resolve_handler(const boost::system::error_code & ec,
                     boost::asio::ip::tcp::resolver::iterator it);

void connect_handler(const boost::system::error_code & ec);

void read_handler(const boost::system::error_code & ec,
                  std::size_t bytes_transferred);

实现

//data_url.cpp

#include <data_url.hpp>
#include <iostream>

data::data() : io_service(), resolver(io_service), socket(io_service)
             , buffer(), host(), path(), port() {}
data d;

void setup_url(std::string hst, std::string pth, std::string prt) {
  d.host = hst;
  d.path = pth;
  d.port = prt;
}

std::vector<char> & get_data_from_url() {
  boost::asio::ip::tcp::resolver::query query(d.host, d.port);
  d.resolver.async_resolve(query, resolve_handler);
  d.io_service.run();
  return d.buffer;
}

void resolve_handler(const boost::system::error_code & ec,
                     boost::asio::ip::tcp::resolver::iterator it) {
  if( !ec ) {
    d.socket.async_connect(*it, connect_handler);
  }
}

void connect_handler(const boost::system::error_code & ec) {
  if( !ec ) {
    boost::asio::write(d.socket,
                       boost::asio::buffer(std::string("GET ") + 
                                           std::string(d.path) +
                                           std::string(" HTTP 1.1\r\n") + 
                                           std::string("Host: ") +
                                           std::string(d.host) +
                                           std::string("\r\n\r\n")));
    boost::system::error_code ec_avail;
    d.buffer.resize(d.socket.available(ec_avail));
    d.socket.async_read_some(boost::asio::buffer(d.buffer), 
                             read_handler);
  }
}

void read_handler(const boost::system::error_code & ec,
                  std::size_t bytes_transferred) {
  if( !ec ) {
    d.socket.async_read_some(boost::asio::buffer(d.buffer), 
                             read_handler);
  }
}

然后运行它

#include <data_url.hpp>

int main(int argc, char *argv[]) {
  setup_url("www.boost.org", "/");
  std::vector<char> data;
  data = get_data_from_url();

  return 0;
}

代码无休止地调用 read_handler 并且永远不会终止。我已经在不同的页面上尝试过,但没有什么区别。

另外,在 content_handler 函数中,我使用 socket.available() 调整向量的大小。这是为了使代码尽可能通用,以便我可以阅读任何页面而不必知道它的大小。但是,当我调用 socket.available() 时,它返回零并将 ec_avail 中的错误代码设置为“未定义错误”。

正如我提到的,我是使用 boost.asio 的新手,显然我在这里遗漏了一些东西。我非常感谢您帮助修复这些错误以及任何其他建议/建议。

I'm new to using boost.asio but I wanted to design a simple routine to get data from a URL and save it to a memory buffer. Based on an example I found, I came up with the following:

//data_url.hpp

#include <boost/asio.hpp>
#include <string>
#include <vector>

struct data {
  data();
  boost::asio::io_service io_service;
  boost::asio::ip::tcp::resolver resolver;
  boost::asio::ip::tcp::socket socket;
  std::vector<char> buffer;
  std::string host;
  std::string path;
  std::string port;
};

void setup_url(std::string hst, 
               std::string pth, 
               std::string prt = "80");

std::vector<char> & get_data_from_url();

void resolve_handler(const boost::system::error_code & ec,
                     boost::asio::ip::tcp::resolver::iterator it);

void connect_handler(const boost::system::error_code & ec);

void read_handler(const boost::system::error_code & ec,
                  std::size_t bytes_transferred);

Implementation

//data_url.cpp

#include <data_url.hpp>
#include <iostream>

data::data() : io_service(), resolver(io_service), socket(io_service)
             , buffer(), host(), path(), port() {}
data d;

void setup_url(std::string hst, std::string pth, std::string prt) {
  d.host = hst;
  d.path = pth;
  d.port = prt;
}

std::vector<char> & get_data_from_url() {
  boost::asio::ip::tcp::resolver::query query(d.host, d.port);
  d.resolver.async_resolve(query, resolve_handler);
  d.io_service.run();
  return d.buffer;
}

void resolve_handler(const boost::system::error_code & ec,
                     boost::asio::ip::tcp::resolver::iterator it) {
  if( !ec ) {
    d.socket.async_connect(*it, connect_handler);
  }
}

void connect_handler(const boost::system::error_code & ec) {
  if( !ec ) {
    boost::asio::write(d.socket,
                       boost::asio::buffer(std::string("GET ") + 
                                           std::string(d.path) +
                                           std::string(" HTTP 1.1\r\n") + 
                                           std::string("Host: ") +
                                           std::string(d.host) +
                                           std::string("\r\n\r\n")));
    boost::system::error_code ec_avail;
    d.buffer.resize(d.socket.available(ec_avail));
    d.socket.async_read_some(boost::asio::buffer(d.buffer), 
                             read_handler);
  }
}

void read_handler(const boost::system::error_code & ec,
                  std::size_t bytes_transferred) {
  if( !ec ) {
    d.socket.async_read_some(boost::asio::buffer(d.buffer), 
                             read_handler);
  }
}

I then run it with

#include <data_url.hpp>

int main(int argc, char *argv[]) {
  setup_url("www.boost.org", "/");
  std::vector<char> data;
  data = get_data_from_url();

  return 0;
}

The code calls read_handler endlessly and never terminates. I've tried it with different pages and that doesn't make a difference.

Also, in the content_handler function I resize the vector using socket.available(). This is to make the code as general as possible so that I could read any page without having to know it's size. But when I call socket.available() it returns zero and sets the error code in ec_avail to "Undefined error".

As I mentioned, I'm new to using boost.asio and obviously I'm missing something here. I'd appreciate help fixing these errors and any other advice/suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我的痛♀有谁懂 2024-12-23 12:32:12

您的套接字不太可能在调用 write 后立即有可用数据,因此您的调整大小方法可能不起作用,然后您使用大小为 0 的缓冲区调用 async_read_some 。

async_read_some 的全部要点是它不需要在异步操作完成之前填充整个缓冲区,因此使用基本块大小类似于 8192 的临时缓冲区,并在每次成功调用读取处理程序后,将读取的数据附加到主缓冲区的末尾。

ASIO 不是一个 HTTP 库,因此如果您使用它通过 HTTP 下载文件,您将需要对数据进行大量处理以解析标头并确定响应的类型,确定内容长度和编码等。

如果您只想将其用于 HTTP 内容,我强烈建议使用 Poco 代替,因为它内置了对 HTTP 流的支持。

Your socket is unlikely to have data available immediately after calling write, so your resizing method is probably not going to work, and you are then calling async_read_some with a buffer of size 0.

The whole point of async_read_some is that it doesn't need to fill the entire buffer before the async operation completes, so use a temporary buffer with a basic block size of something like 8192 and after each successful call to your read handler, append the data read to the end of your primary buffer.

ASIO isn't an HTTP library, so if you're using it to download files via HTTP you'll need to do a lot of processing of the data on the fly to parse the header and determine the type of response it is, determine the content length and encoding, etc.

If you just want to use it for HTTP stuff, I would highly recommend using Poco instead, as it has built-in support for HTTP streams.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文