c++ - Boost Asio 回调不会被调用

标签 c++ boost-asio

我正在使用 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 是异步的。在大多数情况下,客户端从服务器应用程序接收计算数据,并且必须呈现它们的各种图形表示。

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

  1. GUI 必须是响应式的,它不应该被 IO 阻塞。
  2. 客户端可以连接/断开连接。
  3. 流量非常大,每隔几秒就会向客户端发送/刷新数据,并且必须保持响应(根据第 1 项)。

根据 Boost.Asio 文档,

Multiple threads may call io_service::run() to set up a pool of threads from which completion handlers may be invoked. Note that all threads that have joined an io_service's pool are considered equivalent, and the io_service may distribute work across them in an arbitrary fashion.

请注意,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 对象的私有(private) boost::shared_ptr
  • io 是私有(private)的 boost::shared_ptrboost::asio::io_service,
  • connection 是我的连接包装器类的 boost::shared_ptr,并且 connect() 调用使用解析器等来连接套接字,周围有很多这样的例子
  • io_threads 是私有(private)的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() 如果其中的错误代码表示在尝试断开连接后出现错误。

关于c++ - Boost Asio 回调不会被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6806517/

相关文章:

c++ - 错误 LNK1120 : unresolved externals

C++ while(cin >> x){} 与 while(true) {cin >>x;}

c++ - "An existing connection was forcibly closed by the remote host"监听传入数据时

java - Async Boost 写入 Java Socket - 传入字节数组有时部分为 0?

c++ - 是否可以使用单独的线程来读取和写入 Boost.Asio?

c++ - CMakeLists : Adding source files from Github with ExternalProject

c++ - 为什么在 C++ 中,值为 65536 的整数变量的输出为 0 而 < 65536 给出一个负整数,而 > 65536 值给出一个正整数?

c++ - 使用 MsgPack 通过 ZeroMQ (zmqpp) 发送数据给出 'msgpack::v1::insufficient_bytes' 错误

c++ - 您可以在 boost asio 中设置 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项吗?

c++ - 对 udp::socket::async_receive_from 的多个并行调用 - 未定义的行为?