Boost.Asio:异步操作超时

时间:2016-07-18 10:13:25

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

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

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->socket_.lowest_layer().cancel();)。

问题是如果连接超时,将不会立即调用writeHandler。相反,写操作&#34;堆叠&#34;直到第一个到达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->socket_.lowest_layer().cancel();来避免它,但它不起作用。

如何避免分段错误?

1 个答案:

答案 0 :(得分:3)

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

  1. 在您确实知道之前的数据已被写入之前,不要写入数据。您可以将传递给std::string的{​​{1}}实例排队,以防未完成的写入仍处于未决状态,然后在未完成的写入操作完成时实际将它们写入处理程序中。这样,您就不会有多个I / O操作。
  2. 继承NIUserSession::write并将std::enable_shared_from_this而不是shared_from_this()传递给this来电(这是Boost asynchronous TCP daytime server example所做的)。那种等待I / O操作的方式将保留对您的类的引用,并且如果所有这些操作都完成,则将调用析构函数。