我试图异步读取大量数据。
使用"其他"同步模式下的库我需要按块调用一次,因为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;
}
答案 0 :(得分:2)
您使用的async_read
的重载相当于:
boost::asio::async_read(
s, buffers,
boost::asio::transfer_all(), // this is the completion condition
handler);
transfer_all
条件意味着只有在缓冲区已满或连接结束时才会完成。
因此,如果您没有看到调用的回调,可能是因为连接未关闭(来自另一方),或者缓冲区尚未满。
还有其他完成条件,例如transfer_at_least
和transfer_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();