繁体   English   中英

Boost.Asio:异步操作超时

[英]Boost.Asio: Async operations timeout

我的程序充当客户端可以连接的服务器。 一旦客户端连接,他将每隔约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->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->socket_.lowest_layer().cancel();来避免它this->socket_.lowest_layer().cancel(); 在第一次异步操作失败后直接,但它不起作用。

如何避免分段错误?

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

  1. 在您确实知道先前已写入数据之前,请勿写入数据。 您可以对传递给NIUserSession::writestd::string实例进行NIUserSession::write ,以防未完成的写仍处于未决状态,然后在未完成的写操作完成时将它们实际写入处理程序中。 这样,您就不会有多个I / O操作。
  2. 继承自std::enable_shared_from_this并将std::enable_shared_from_this shared_from_this()而不是this传递给async_write调用(这是Boost异步TCP日间服务器示例所做的)。 这种方式等待I / O操作将保持对您的类的引用,并且如果所有这些操作都完成,则将调用析构函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM