[英]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.