[英]asio - Wait for async operations to finish
我正在使用boost.asio,我有一個需要處理多個連接的簡單服務器。 在開始“已連接”狀態之前,我需要在有限的時間內與客戶端進行握手。 我正在為握手的每一步使用鏈式異步操作,因為我需要使用一個計時器(據我所知,我不能用同步讀寫操作)。 我需要一種方法來阻止每個連接,直到截止時間計時器結束或握手成功,而不會阻塞服務器。
有沒有辦法實現這個目標?
更新一些代碼來澄清事情
簡單的服務器
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();
}
connection-> Accept(socket)解釋
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_service
( stop()
- > reset()
- > run()
)才會調用它,這根本不是解決方案。
我想我錯過了關於Asio的一些事情,如果有人能幫助我,我會很高興。
你的示例代碼不完整,所以我不能保證我的答案是一個解決方案,但我會指出一些我認為是問題的東西。
第1點 - io_service
不僅僅是繼續運行。 如果它認為沒有更多的工作要做(沒有提示),那么::run()
將退出,並且由於你不期望它,你將會得到意想不到的行為。 您需要通過創建和保持io_service::work
對象的活動來防止它耗盡工作。 來自文檔:
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
...
更多關於這一點 。
其次,我關心如何維持CCon
對象的生命周期。 誰有責任讓它活着? 我問,因為你綁定到this
內部,所以你在內部產生異步回調,但顯然依賴於外部對象,以確保在回調返回時this
是活着的。 如果你沒有正確地做到這一點,你將會得到未定義的行為,這並不一定意味着你會得到一個大的崩潰和錯誤代碼,但也許某種程度上處理程序完成或永久掛起,或者由於未定義的狀態,一些其他奇怪的不確定行為。
基於這里不完整的代碼,看起來沒有什么CCon
在外部保持活力,這意味着事情可能會超出范圍並被破壞。 我猜你在你的服務器上總是得到“連接不被接受”,如果有的話。 如果你分解你在這里的代碼,你會產生一個包含在shared_ptr
的CCon
,然后調用::Accept()
,然后調用非阻塞的異步方法,這些方法可以立即完成,或者從現在開始100年。 由於它們是非阻塞的 ,代碼將立即進入if(connectionAccepted)
語句,因此立即返回另一個方式,此時你的CCon
的shared_ptr
超出了服務器handle_accept
的范圍,引用計數得到遞減到0並調用析構函數。
您應該做的是使CCon
繼承自std::enable_shared_from_this
或boost::enable_shared_from_this
並且在CCon
內部綁定的所有異步回調中,您應該綁定到shared_from_this()
,這將從綁定將另一個shared_ptr
給cue ,遞增共享CCon
對象的引用計數,並保證CCon
的生命周期至少延伸到完成處理程序。
第三,我認為你的設計方法不是最好的解決方案,作為旁注。 您不應該強制每個其他可能的傳入連接等待以前的連接經歷一些身份驗證過程。 您正在阻止接受者為新客戶工作,直到之前的客戶端與服務器進行一些交談。 這是一個完全不必要的瓶頸。
我相信你這樣做是因為你想在::server
對象級別確定客戶端是否正確地通過了身份驗證過程。 你應該只是將一個函數或其他東西傳遞給CCon::Accept(...)
方法,如果你真的需要服務器知道任何東西,它可以調用它向服務器報告。 復制asio模型並將Accept
方法更改為AsyncAccept
,使其成為非阻塞,並在完成時為其提供回調,此時您可以檢查其最終狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.