Boost Asio回调不会被调用

时间:2011-07-24 11:30:54

标签: c++ boost-asio

我正在使用Boost.Asio进行网络操作,他们必须(实际上可以,没有复杂的数据结构或任何东西)保持相当低的水平,因为我无法负担序列化开销(和libs)的奢侈我发现确实提供了足够好的性能似乎非常适合我的情况)。

问题在于我正在从客户端进行异步写入(在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);
    }
}

即使服务器收到所有数据,也不会调用回调。任何人都可以想到为什么会这样做吗?

P.S。这个连接有一个包装器,是的,可能会有一个连接器。一两天前放弃它,因为我找不到这个回调的问题。

2 个答案:

答案 0 :(得分:2)

正如所建议的那样,发布一个我认为最合适的解决方案(至少目前为止)。

客户端应用程序是用QT编写的,我需要IO是异步的。在大多数情况下,客户端从服务器应用程序接收计算数据,并且必须呈现它们的各种图形表示。

现在,需要考虑一些关键方面:

  1. GUI必须是响应式的,不应该被IO阻止。
  2. 可以连接/断开客户端。
  3. 流量非常紧张,数据每隔几秒就会被发送/刷新到客户端,并且必须保持响应(按照第1项)。
  4. 根据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);
        }
    }
    

    连接&amp;启动IO,其中:

    • work是传递的boost::shared_ptr对象的私有boost::asio::io_service::work
    • ioboost::shared_ptr的私人boost::asio::io_service
    • connection是我的连接包装类的boost::shared_ptrconnect()调用使用解析器等来连接套接字,有大量的例子
    • 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)或者从{{{ 1}}如果其中的错误代码在尝试断开连接后表示错误。

答案 1 :(得分:1)

我遇到了类似的问题(回调未被触发)但情况与此问题不同(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()调用生成线程)

希望有所帮助。