2015-10-27 226 views
3

我正在使用boost.asio,并且我有一个需要处理多个连接的简单服务器。在开始“连接”状态之前,我需要在有限的时间内与客户进行握手。我为握手的每一步使用了链式异步操作,因为我需要使用定时器和(据我所知我无法在同步读取和写入时执行此操作)。我需要一种方法来阻止每个连接,直到截止日期计时器结束或握手成功,而不会阻塞服务器。asio - 等待异步操作完成

有什么办法可以达到这个目的吗?

UPDATE一些代码,以澄清事情

一个简单服务器

typedef boost::asio::ip::tcp::socket sock; 

class server 
{ 
public: 
    server() : _ios(), _acceptor(_ios) 
    { 
     boost::asio::ip::tcp::resolver resolver(_ios); 
     boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), PORT); 

     _acceptor.open(endpoint.protocol()); 
     _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); 
     _acceptor.bind(endpoint); 
     _acceptor.listen(); 

     do_accept(); 
    } 

    void run() 
    { 
     _ios.run(); 
    } 

private: 
    void do_accept() 
    { 
     auto socket = std::make_shared<TSock>(_ios); 
     _acceptor.async_accept(*socket, std::bind(&server::handle_accept, 
                this, socket, std::placeholders::_1)); 
    } 

    void handle_accept(std::shared_ptr<sock> socket, const boost::system::error_code& ec) 
    { 
     auto connection = std::make_shared<CCon>(); 

     if (connection->Accept(socket)) 
     { 
      std::cout << "Connection accepted" << std::endl; 
     } 
     else 
     { 
      std::cout << "Connection not accepted" << std::endl; 
     } 

     do_accept(); 
    } 

    boost::asio::io_service   _ios; 
    boost::asio::ip::tcp::acceptor _acceptor; 

    std::set<std::shared_ptr<CCon>> _connections; 
}; 

int32_t main(int32_t argc, char *argv[]) 
{ 
    server s; 
    s.run(); 
} 

连接 - >接受(插座)解释

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) 
    } 
} 

SendGreeting()包含

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

问题是WaitForResp永远不会被调用。如果在设置新的处理程序后重新启动io_servicestop() - >reset() - >run()),它只会被调用,这根本不是解决方案。

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

+0

我需要使用异步函数,因为我需要一个握手计时器,但我还需要等待(阻止)我的代码的一部分,以完成握手或计时器结束。 – Bituki

+1

我试过使用期货,但不知何故,握手卡在第一个处理程序,直到'未来'完成其等待时间,然后所有的握手运行(也许我需要有io_service运行在另一个线程?)。我需要一些时间来简化我的代码并将其发布到此处,但我会尽力说清楚。 – Bituki

+0

@TechnikEmpire我添加了一些代码。我希望现在更清楚。 – Bituki

回答

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的活性,这意味着事情可能会超出范围并被破坏。我猜测你的服务器总是会出现“连接不被接受”,如果有的话。如果你分解了你在这里的代码,你产生了一个包装在shared_ptr中的CCon,然后调用::Accept(),这反过来调用非阻塞异步方法,可以立即完成,或从现在起100年。由于它们是非阻塞,代码将立即进入if(connectionAccepted)语句,因此立即返回另一路,此时您的shared_ptrCCon超出了服务器handle_accept的范围,ref计数将递减为0并且调用析构函数。

什么,你应该做的是从std::enable_shared_from_thisboost::enable_shared_from_this和所有CCon内部结合异步回调使得CCon继承,你应该绑定到shared_from_this(),这将养活另一个shared_ptr到从绑定的线索,增加裁判计算共享的CCon对象并保证CCon的生存期至少延伸到完成处理程序中。

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

我相信你这样做是因为你想在::server对象级别确定客户端是否已经正确地通过了认证过程。如果你确实需要服务器知道任何事情,你应该只是传递一个函数或其他东西到它可以调用的方法来向服务器报告。复制asio模型并将Accept方法更改为AsyncAccept,使其成为非阻塞状态,并在完成时给它一个回调,此时您可以检查其最终状态。

+0

感谢您的回答,但是:1-'work'在这里可能没有必要,因为我在handle_accept()的末尾调用了'do_accept()',因此''io_service'总是有事可做,就像[here] (http://www.boost.org/doc/libs/1_59_0/doc/html/boost_asio/example/cpp11/http/server/server.cpp)。 2 - 感谢您的建议,您对此完全正确,但在更改此设置后,服务器的行为仍然是相同的......,这不是导致我出现问题的原因。 – Bituki

+0

@Bituki你有没有看到关于正确绑定到'CCon'里面'shared_from_this'的部分?因为从你发布的代码中,'CCon'的'shared_ptr'会很快掉到范围之外,析构函数将被调用。在“〜CCon”中打印“销毁”到控制台进行验证。 –

+0

是的,我在第二点说我已经实施了你的建议,但这并没有解决我的问题。 – Bituki