C++11 boost asio async\u read no调用回调

C++11 boost asio async\u read no调用回调,c++11,asynchronous,tcp,network-programming,boost-asio,C++11,Asynchronous,Tcp,Network Programming,Boost Asio,我正在尝试异步读取大量数据 对于同步模式下的“其他”库,我需要按块调用读取多次,因为tcp是一个流,并且窗口大小是有限的 因此,我认为需要使用boost asio的async_read,但回调是针对短数据(例如:1024)调用的,当数据量增加时(例如:max_length=80000>65536),回调不被调用,那么我做错了什么?这是一个产生我的问题的示例: #include <cstdio> #include <thread> #include <boost/a

我正在尝试异步读取大量数据

对于同步模式下的“其他”库,我需要按块调用读取多次,因为tcp是一个流,并且窗口大小是有限的

因此,我认为需要使用boost asio的
async_read
,但回调是针对短数据(例如:1024)调用的,当数据量增加时(例如:
max_length=80000>65536
),回调不被调用,那么我做错了什么?这是一个产生我的问题的示例:

#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间ba=boost::asio;
枚举{max_length=1024};
int main(){
ba::io_服务io_服务;
ba::ip::tcp::socket sk(io_服务);
ba::ip::tcp::解析器解析器(io_服务);
ba::连接(sk,
resolver.resolve(ba::ip::tcp::resolver::query{ba::ip::tcp::v4(),
"127.0.0.1",
"8881"}));
字符请求[最大长度];
ba::异步读取(sk,
ba::缓冲区(请求,最大长度),
[](const boost::system::error\u code&err,std::size\t){
如果(!err){
std::printf(“无错误回调!\n”);
}否则{
std::fprintf(stderr,“带错误的回调!\n”);
}
});
io_服务。运行_one();
//在异步线程中等待转换。
std::this_thread::sleep_for(std::chrono::毫秒{1000});
返回退出成功;
}

您正在使用的
异步读取的重载相当于:

boost::asio::async_read(
    s, buffers,
    boost::asio::transfer_all(), // this is the completion condition
    handler);
transfer\u all
条件意味着只有当缓冲区已满或连接结束时,传输才会完成

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

还有其他完成条件,例如
transfer\u至少
transfer\u精确
,以及其他
异步读取*
功能。如果不知道你想做什么,就很难推荐你需要的


您也可以调用套接字的
async\u read\u some
方法,它的行为更像传统的低级别BSD套接字(只要读取某个内容,就会调用回调)。

您正在使用的
async\u read
的重载相当于:

boost::asio::async_read(
    s, buffers,
    boost::asio::transfer_all(), // this is the completion condition
    handler);
transfer\u all
条件意味着只有当缓冲区已满或连接结束时,传输才会完成

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

还有其他完成条件,例如
transfer\u至少
transfer\u精确
,以及其他
异步读取*
功能。如果不知道你想做什么,就很难推荐你需要的


您还可以调用套接字的
async\u read\u some
方法,它的行为更像传统的低级别BSD套接字(一旦读取了某个内容,就会调用回调)。

这要感谢2015年2月24日的Antony Polukhin

尝试使用io_service.run();而不是io_服务。运行_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(std::chrono::毫秒{1000})

简要说明: async_read操作通过零次或多次调用流的async_read_some函数来实现。调用io_service.run_one()时,您请求只执行一个调用-第一个对异步\u read_some的调用(将跳过其他调用)。这就是为什么您只接收65535个字节,而不调用回调(回调将在最后一次异步读取完成后调用)


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

感谢2015年2月24日的Antony Polukhin

尝试使用io_service.run();而不是io_服务。运行_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(std::chrono::毫秒{1000})

简要说明: async_read操作通过零次或多次调用流的async_read_some函数来实现。调用io_service.run_one()时,您请求只执行一个调用-第一个对异步\u read_some的调用(将跳过其他调用)。这就是为什么您只接收65535个字节,而不调用回调(回调将在最后一次异步读取完成后调用)


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

确保
io\u服务
(最近称为
io\u上下文
)在
async\u read
调用后重新启动并运行:

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

确保
io\u服务
(最近称为
io\u上下文
)在
async\u read
调用后重新启动并运行:

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

我通过使用boost::asio::ip::tcp::socket中的成员函数async_read_some解决了这个问题,但我不明白为什么您的建议不适用于我的,我尝试了boost::asio::transfer_justice()、boost::asio::transfer_all()、boost::asio::transfer_至少()。有人能解释这是为什么吗?我做错了什么?实际发送了多少字节?您至少使用了多少字节来传输?如果只发送了一个字节,并且您要求至少接收2个字节,那么您仍然不会看到调用回调(直到连接结束)。如果您需要的逻辑是
async\u read\u some
方法,那么使用该方法没有什么错;它应该相当于使用
transfer\u至少(1)
。好的,如果服务器发送1字节,我尝试读取2字节