提升asio async_read没有调用回调

时间:2015-02-22 19:41:54

标签: c++11 asynchronous tcp network-programming boost-asio

我试图异步读取大量数据。

使用"其他"同步模式下的库我需要按块调用一次,因为tcp是一个流,窗口大小有限。

所以我认为需要使用来自boost asio的async_read,但是当数据量增长时(例如:max_length = 80000 > 65536),回调被调用为短数据(例如:1024)回调没有被调用,所以我做错了什么?,这是一个产生我的问题的例子:

#include <cstdio>
#include <thread>

#include <boost/asio/io_service.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/ip/tcp.hpp>

namespace ba = boost::asio;

enum { max_length = 1024 };

int main() {
  ba::io_service io_service;
  ba::ip::tcp::socket sk(io_service);
  ba::ip::tcp::resolver resolver(io_service);
  ba::connect(sk,
              resolver.resolve(ba::ip::tcp::resolver::query{ba::ip::tcp::v4(),
                                                            "127.0.0.1",
                                                            "8881"}));
  char request[max_length];
  ba::async_read(sk,
                 ba::buffer(request, max_length),
                 [](const boost::system::error_code& err, std::size_t){
    if (!err) {
      std::printf("Callback without error!\n");
    } else {
      std::fprintf(stderr, "Callback with error!\n");
    }
  });
  io_service.run_one();

  // wait the transtition in the async thread.
  std::this_thread::sleep_for(std::chrono::milliseconds{1000});
  return EXIT_SUCCESS;
}

3 个答案:

答案 0 :(得分:2)

您使用的async_read的重载相当于:

boost::asio::async_read(
    s, buffers,
    boost::asio::transfer_all(), // this is the completion condition
    handler);

transfer_all条件意味着只有在缓冲区已满或连接结束时才会完成。

因此,如果您没有看到调用的回调,可能是因为连接未关闭(来自另一方),或者缓冲区尚未满。

还有其他完成条件,例如transfer_at_leasttransfer_exactly,以及其他async_read*函数。如果不确切知道自己想做什么,很难推荐你需要的那个。

您也可以调用套接字的async_read_some方法,它的行为更像传统的低级BSD套接字(一旦读取内容就会调用回调。)

答案 1 :(得分:1)

感谢来自https://plus.google.com/communities/106814259809358442744 24 de Feb的Antony Polukhin。 de 2015。

尝试使用io_service.run();而不是io_service.run_one();.另外,修复错误检查:

// (err == boost::asio::error::eof) - Connection
// closed cleanly by peer
if (!err || err == ba::error::eof) {
  std::printf("Callback without error!\n");
} else {
  std::fprintf(stderr, "Callback with error!\n");
}

此外,您似乎不需要以下行: 的std :: this_thread :: sleep_for(标准::计时::毫秒{1000});

简短说明: async_read操作是根据对流的async_read_some函数的零次或多次调用实现的。当调用io_service.run_one()时,您请求只执行一次调用 - 第一次调用async_read_some(将跳过其他调用)。这就是为什么你只收到65535个字节并且没有调用回调的原因(在最后一个async_read_some结束后将调用回调)。

io_service.run()和io_service.run_one()在当前线程中运行操作并阻塞线程,直到操作完成,因此不需要调用sleep。

答案 2 :(得分:0)

请确保io_service(最近称为io_context)在async_read调用后重新启动并运行:

io_service.restart();
io_service.run_one();