【问题标题】:Boost.Asio: Async operations timeoutBoost.Asio:异步操作超时
【发布时间】:2016-07-18 10:13:24
【问题描述】:

我的程序充当客户端可以连接的服务器。一旦客户端连接,他将每隔约 5 秒从服务器获取更新。这是每 5 秒调用一次以将新数据发送到客户端的 write 函数:

void NIUserSession::write(std::string &message_orig)
{
    std::cout << "Writing message" << std::endl;

    std::shared_ptr<std::string> message = std::make_shared<std::string>( message_orig );
    message->append("<EOF>");
    boost::system::error_code ec;
    boost::asio::async_write(this->socket_, boost::asio::buffer(*message),
        boost::asio::transfer_all(), boost::bind(&NIUserSession::writeHandler,
               this, boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred(),
               message 
               ));
}

void NIUserSession::writeHandler(const boost::system::error_code &error, std::size_t bytes_transferred, std::shared_ptr<std::string> message)
{
    std::cout << "Write Handler" << std::endl;
    if(error)
    {
        std::cout << "Write handler error: " << error.message() << std::endl;
        this->disconnect();
    }
}

void NIUserSession::disconnect()
{
    std::cout << "Disconnecting client, cancling all write and read operations." << std::endl;
    this->socket_.lowest_layer().cancel();

    delete this;
}

如果写入操作出错,服务器和客户端之间的连接将关闭,所有异步操作都将被取消 (this-&gt;socket_.lowest_layer().cancel();)。

问题是如果连接超时,writeHandler 不会立即被调用。相反,写入操作“堆叠”直到第一个到达writeHandler

这应该是程序的正常输出:

Writing message
Write Handler
... Other stuff ...
... Other stuff ...
Writing message
Write Handler

如果连接超时,会发生以下情况:

Writing message
Write Handler
Write handler error: Connection timed out
Disconnecting client, cancling all write and read operations.
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Write Handler
Segmentation fault

最后,出现分段错误。我认为这是因为 disconnect 被调用,而其他异步操作仍在进行中。 我以为我可以在第一次异步操作失败后直接使用this-&gt;socket_.lowest_layer().cancel(); 来避免它,但它不起作用。

如何避免分段错误?

【问题讨论】:

    标签: c++ asynchronous boost segmentation-fault boost-asio


    【解决方案1】:

    好吧,您不应该在取消操作时删除 this,因为挂起的 I/O 操作的回调仍然会被调用,然后访问 this 会导致未定义的行为。有多种方法可以解决这个问题:

    1. 在您真正知道之前的数据已被写入之前,请勿写入数据。您可以将传递给NIUserSession::writestd::string 实例排队,以防未完成的写入仍处于挂起状态,然后在未完成的写入操作完成时将它们实际写入处理程序中。这样一来,您就不会进行多个 I/O 操作。
    2. std::enable_shared_from_this 继承并将shared_from_this() 而不是this 传递给async_write 调用(这是Boost asynchronous TCP daytime server example 所做的)。这样,待处理的 I/O 操作将保留对您的类的引用,并且如果所有操作都完成,则将调用析构函数。

    【讨论】:

    • 不会导致分段错误。它导致Undefined Behaviour。否则,+1
    • 在使用异步操作时,您需要非常小心对象的生命周期。 boost::asio examples 使用 shared_ptr 有充分的理由,请参阅:boot asio async function and shared ptrs
    • @sehe - 谢谢,已编辑 :) 使用不正确的措辞我很糟糕。
    • 谢谢,我会尽快检查并回复:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 2021-05-31
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    相关资源
    最近更新 更多