Boost.asio socket - 为什么没有可用的字节

时间:2011-11-17 23:12:44

标签: c++ boost-asio

我是使用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的新手,显然我在这里遗漏了一些东西。我很感激帮助解决这些错误以及任何其他建议/建议。

1 个答案:

答案 0 :(得分:3)

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

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

ASIO不是一个HTTP库,所以如果你用它来通过HTTP下载文件,你需要动态地处理大量的数据来解析标题并确定它的响应类型是,确定内容长度和编码等。

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