gpt4 book ai didi

c++ - asio - 等待异步操作完成

转载 作者:太空狗 更新时间:2023-10-29 23:00:36 25 4
gpt4 key购买 nike

我正在使用 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);
...

更多信息 here .

其次,我很关心 CCon保持对象生命周期。谁负责让它活着?我问是因为你绑定(bind)到 this在它里面,所以你在内部生成异步回调,但显然依赖外部对象来确保 this如果回调返回并且当回调返回时,它还活着。如果你没有正确地做到这一点,你会得到未定义的行为,这并不一定意味着你会得到一个大的崩溃和错误代码,但也许处理程序会以某种方式完成或永远挂起,或者由于未定义的状态,还有一些其他奇怪的不确定行为。

根据此处不完整的代码,看起来没有任何内容保留 CCon在外部还活着,这意味着事物可能超出范围并被破坏。我猜你总是在你的服务器上得到“连接不被接受”,如果有的话。如果你分解你在这里的代码,你会产生一个 CCon包裹在 shared_ptr 中, 然后调用 ::Accept() ,它又会调用非阻塞 异步方法,这些方法可能立即完成,也可能在 100 年后完成。由于它们是非阻塞,因此代码将进入 if(connectionAccepted)立即声明并因此立即以另一种方式返回,此时你的shared_ptrCCon超出服务器范围 handle_accept ,引用计数减少到 0 并调用析构函数。

你应该做的是制作 CCon继承自 std::enable_shared_from_thisboost::enable_shared_from_this在所有 CCon 的异步回调中内部绑定(bind),你应该绑定(bind)到 shared_from_this() ,这将提供另一个 shared_ptr从绑定(bind)进入提示,增加共享 CCon 的引用计数对象并保证 CCon 的生命周期至少扩展到完成处理程序。

第三,作为旁注,我认为您的设计方法不是最佳解决方案。您不应该强制所有其他可能的传入连接等待先前的连接通过某些身份验证过程。在前一个客户端与服务器进行一些对话之前,您正在阻止接受器为新客户端完成其工作。这是一个完全不必要的瓶颈。

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

关于c++ - asio - 等待异步操作完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33374856/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com