asio - 等待异步操作完成

时间:2015-10-27 17:37:25

标签: c++ asynchronous boost-asio

我正在使用boost.asio,我有一个需要处理多个连接的简单服务器。在开始连接之前#34;状态,我需要在有限的时间内与客户进行握手。我正在为握手的每一步使用链式异步操作,因为我需要使用定时器(据我所知,我不能用同步读写操作)。我需要一种方法来阻止每个连接,直到截止时间计时器结束或握手成功,而不会阻塞服务器。

有没有办法实现这个目标?

更新一些代码澄清事情

一个简单的服务器

bool CCon::Accept(<std::shared_ptr<sock>> tcpSocket)
{
    // set handshake sequence
    SendGreeting();

    // I NEED TO WAIT HERE UNTIL connectionAccepted gets a value

    if (connectionAccepted)
    {
        // Connection Accepted
        return(true)
    }
    else
    {
        //Connection Rejected
        return(false)
    }
}

connection-&gt;接受(套接字)解释

boost::asio::async_write(*tcpSocket, 
                         boost::asio::buffer(oBuff,bytesBuffered),
                         std::bind(&CCon::WaitForResp, 
                                   this, std::placeholders::_1));

SendGreeting()包含

io_service

问题是WaitForResp永远不会被调用。如果我在设置新处理程序后重新启动stop()reset() - &gt; run() - &gt; {{1}}),则只会调用它,这不是解决方法所有

我想我错过了关于Asio的一些事情,如果有人能帮助我,我会很高兴。

1 个答案:

答案 0 :(得分:1)

您的示例代码并不完整,因此我无法保证我的答案是一个解决方案,但我会指出一些我认为是问题的事情。

第1点 - io_service不会继续运行。如果它认为没有更多工作要做(提示中没有任何内容),那么::run()将会退出,并且由于您不期望它不会,您将会获得意外行为。您需要通过创建并保持io_service::work对象的活动来防止它耗尽工作。来自文档:

boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
...

有关here的更多信息。

其次,我关注如何维护CCon对象的生命周期。谁有责任让它活着?我问,因为你绑定到它内部的this,所以你在内部产生异步回调,但显然是依赖外部对象来确保this在有效时回调返回。如果您未能正确执行此操作,您将会获得未定义的行为,这并不一定意味着您将获得大量崩溃和错误代码,但可能会以某种方式由于未定义的状态,处理程序完成或挂起或其他一些奇怪的不确定行为。

基于这里不完整的代码,看起来没有什么能使CCon在外部保持活力,这意味着事情可能会超出范围并被破坏。我猜你总是得到&#34;连接不被接受&#34;在您的服务器中,如果有的话。如果你分解了这里的代码,你会在CCon中生成shared_ptr,然后调用::Accept(),然后调用非阻塞异步可能立即完成的方法,或从现在起100年后完成的方法。由于他们已经非阻止,因此代码会立即进入if(connectionAccepted)语句,因此会立即以另一种方式返回,此时您的shared_ptr CCon超出服务器handle_accept中的范围,引用计数递减为0并且调用析构函数。

您应该做的是让CCon继承自std::enable_shared_from_thisboost::enable_shared_from_this,并且在CCon内部绑定的所有异步回调中,您应该绑定到{{ 1}},它会将另一个shared_from_this()提供给绑定中的提示,增加共享shared_ptr对象的引用计数,并保证CCon的生命周期至少延伸到完成处理程序。

第三,我认为您的设计方法并非最佳解决方案,作为旁注。您不应该强制每个其他可能的传入连接等待以前的连接经历一些身份验证过程。你为新客户做好了工作,直到前一个客户端与服务器进行了一些交谈。这是一个完全不必要的瓶颈。

我相信您正在执行此操作,因为您希望在CCon对象级别确定客户端是否已正确通过身份验证过程。您应该只是将一个函数或其他东西传递给它可以调用的::server方法,以便向服务器报告内容,如果您确实需要服务器知道任何内容。复制asio模型并将CCon::Accept(...)方法更改为Accept,将其设置为非阻塞,并在完成时为其提供回调,此时您可以检查其最终状态。