提升 Asio 回调未被调用
Boost Asio callback doesn't get called
我正在使用 Boost.Asio 进行网络操作,它们必须(实际上,可以,没有复杂的数据结构或任何东西(保持相当低的水平,因为我负担不起序列化开销的奢侈(我发现确实提供了足够好性能的库似乎不适合我的情况(。
问题在于我从客户端进行的异步写入(在 QT 中,但这在这里可能无关紧要(。async_write
中指定的回调永远不会被调用,我完全不知道为什么。代码为:
void SpikingMatrixClient::addMatrix() {
std::cout << "entered add matrix" << std::endl;
int action = protocol::Actions::AddMatrix;
int matrixSize = this->ui->editNetworkSize->text().toInt();
std::ostream out(&buf);
out.write(reinterpret_cast<const char*>(&action), sizeof(action));
out.write(reinterpret_cast<const char*>(&matrixSize), sizeof(matrixSize));
boost::asio::async_write(*connection.socket(), buf.data(),
boost::bind(&SpikingMatrixClient::onAddMatrix, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
调用第一次写入。回调为
void SpikingMatrixClient::onAddMatrix(const boost::system::error_code& error, size_t bytes_transferred) {
std::cout << "entered onAddMatrix" << std::endl;
if (!error) {
buf.consume(bytes_transferred);
requestMatrixList();
} else {
QString message = QString::fromStdString(error.message());
this->ui->statusBar->showMessage(message, 15000);
}
}
即使服务器收到所有数据,也不会调用回调。谁能想到它为什么会这样做的任何原因?
附言该连接有一个包装器,是的,可能会再次有一个。一两天前放弃了它,因为我找不到这个回调的问题。
正如建议的那样,发布一个我认为最合适的解决方案(至少目前是这样(。
客户端应用程序是用QT编写的,我需要IO是异步的。在大多数情况下,客户端从服务器应用程序接收计算数据,并且必须呈现它们的各种图形表示。
现在,需要考虑一些关键方面:
- GUI 必须是响应式的,它不应该被 IO 阻止。
- 客户端可以连接/断开连接。
- 流量非常强烈,数据每隔几秒钟就会发送/刷新一次到客户端,并且必须保持响应(根据第 1 项(。
根据Boost.Asio文档,
多个线程可以调用 io_service::run(( 来设置一个池 可从中调用完成处理程序的线程。 请注意,已加入io_service池的所有线程都被视为等效的,io_service可能会以任意方式在它们之间分配工作。
请注意,io_service.run()
阻止,直到io_service耗尽工作。
考虑到这一点,明确的解决方案是从另一个线程运行io_service.run()
。相关的代码片段是
void SpikingMatrixClient::connect() {
Ui::ConnectDialog ui;
QDialog *dialog = new QDialog;
ui.setupUi(dialog);
if (dialog->exec()) {
QString host = ui.lineEditHost->text();
QString port = ui.lineEditPort->text();
connection = TcpConnection::create(io);
boost::system::error_code error = connection->connect(host, port);
if (!error) {
io = boost::shared_ptr<boost::asio::io_service>(new boost::asio::io_service);
work = boost::shared_ptr<boost::asio::io_service::work>(new boost::asio::io_service::work(*io));
io_threads.create_thread(boost::bind(&SpikingMatrixClient::runIo, this, io));
}
QString message = QString::fromStdString(error.message());
this->ui->statusBar->showMessage(message, 15000);
}
}
用于连接和启动 IO,其中:
-
work
是传递boost::asio::io_service::work
对象的私有boost::shared_ptr
, -
io
是boost::asio::io_service
的私人boost::shared_ptr
, -
connection
是我的连接包装类的boost::shared_ptr
,并且connect()
调用使用解析器等来连接套接字,周围有很多这样的例子 io_threads
是一个私人boost::thread_group
.
如果需要,当然可以用一些 typedef 来缩短它。
TcpConnection
是我自己的连接包装器实现,它现在有点缺乏功能,我想我可以在恢复时将整个线程的东西移入其中。无论如何,这个片段应该足以得到这个想法......
断开部分是这样的:
void SpikingMatrixClient::disconnect() {
work.reset();
io_threads.join_all();
boost::system::error_code error = connection->disconnect();
if (!error) {
connection.reset();
}
QString message = QString::fromStdString(error.message());
this->ui->statusBar->showMessage(message, 15000);
}
- 销毁工作对象,以便
io_service
最终会耗尽工作, - 线程是联接的,这意味着所有工作在断开连接之前都已完成,因此数据不应该损坏,
disconnect()
在后台的套接字上调用shutdown()
和close()
,如果没有错误,则会销毁连接指针。
请注意,如果在此代码段中断开连接时出现错误,则没有错误处理,但可以通过检查错误代码(看起来更像 C(或从disconnect()
抛出(如果其中的错误代码表示错误(从 中抛出尝试断开连接后的错误。
我遇到了类似的问题(回调未触发(,但情况与这个问题不同(io_service
有工作但仍然不会解雇处理程序(。无论如何,我都会发布这个,也许它会帮助某人。
在我的程序中,我设置了一个async_connect()
,然后是io_service.run()
,它按预期阻塞。
async_connect()
按预期进入on_connect_handler()
,这反过来又触发了async_write()
.
on_write_complete_handler()
不会触发,即使连接的另一端已经收到了所有数据,甚至已经发回了响应。
我发现这是由于我将程序逻辑放在on_connect_handler()
中引起的。具体来说,在建立连接后,在我调用async_write()
之后,我进入了一个无限循环来执行任意逻辑,不允许on_connect_handler()
退出。我认为这会导致io_service
无法执行其他处理程序,即使满足他们的条件,因为它卡在这里。(我有很多误解,认为io_service
会为每个async_x()
调用自动生成线程(
希望有帮助。
- 用于在回调中调用解析器的设计模式
- 从不同的 cpp 调用回调函数会导致bad_function_call
- 处理类内的回调时,必须调用对非静态成员函数的引用
- MSVC __debugbreak() 与 openGL 错误回调一起使用时不会产生调用堆栈
- LIBEV 非阻滞套接字连续调用回调
- 共享指针和回调注册的结构.由于我之外的原因调用回调时,原始指针值发生了变化
- 统一处理具有协变类型的函数指针(如何使用派生类型调用回调?
- 在本机节点中的回调中调用回调
- boost asio,async_read和acync_write未调用回调
- cuda流:流执行后未调用回调
- VDS(虚拟磁盘服务)COM接口通知-仅在注销期间调用回调(接收器)(Unadvise)
- 提升 ASIO,async_read_some未调用回调
- 如何在成员函数线程中调用回调
- 从c++向目标c调用回调函数
- c++调用回调后删除对象
- 可调用(回调)作为类模板参数的模板
- 在异步API (c++)中,如何保证API在调用回调之前返回
- 装饰器模式:如何从核心类中调用(回调)装饰器包装器的一些成员
- Cython使用python-c-api调用回调segfault
- 为什么boost asio async_read_some在特定情况下不调用回调