2015-10-27 238 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