我正在尝试将解析器添加到我的UDP套接字连接类中。我使用连接/发送接口,我想在连接中解析和连接,并在发送中发送数据。我希望回调给予的resolve函数能给出一个端点范围,我应该遍历它以找到可用的端点。所以我实现了connect方法,它检查所有端点,但它看起来非常庞大和复杂。
void UdpConnection::Connect()
{
std::promise<void> connectPromise;
auto connectFuture = connectPromise.get_future();
auto handleResolveCallback = [this, p = std::move(connectPromise), self = shared_from_this()]
(const boost::system::error_code& ec, boost::asio::ip::udp::resolver::iterator endpoint_iterator) mutable
{
if (ec)
{
p.set_exception(std::make_exception_ptr(boost::system::system_error(ec)));
}
else
{
while (endpoint_iterator != boost::asio::ip::udp::resolver::iterator())
{
try {
std::promise<void> connectPromise2;
auto connectFuture2 = connectPromise2.get_future();
boost::asio::ip::udp::endpoint iter = *endpoint_iterator;
boost::asio::post(m_socket.get_executor(),
[this, p = std::move(connectPromise2), self = shared_from_this(), iter]() mutable { DoConnect(std::move(p), std::move(iter)); });
connectFuture2.get();
break;
}
catch (const std::exception& ex)
{
std::cout<< "Run-time exception: " << ex.what() << std::endl;
++endpoint_iterator;
}
};
}
};
m_resolver.async_resolve(boost::asio::ip::udp::v4(), m_to.c_str(), m_port.c_str(), std::move(handleResolveCallback));
connectFuture.get();
}
void UdpConnection::DoConnect(std::promise<void> p, boost::asio::ip::udp::endpoint iter)
{
auto handleConnect = [p = std::move(p), self = shared_from_this()](const boost::system::error_code& ec) mutable
{
EKA_TRACE_DEBUG_EX(self->GetTracer()) << TR << "Connect: " << ec.message();
if (ec)
p.set_exception(std::make_exception_ptr(boost::system::system_error(ec)));
else {
p.set_value();
}
};
m_socket.async_connect(iter, std::move(handleConnect));
}
我不知道为什么它不调用DoConnect,而是停留在connectFuture.get()中。痕迹:
@asio|1696946039.156806|0*1|[email protected](blk=never,rel=fork)
@asio|1696946039.156806|>1|
@asio|1696946039.157804|>0|
@asio|1696946039.874930|0*2|[email protected](blk=never,rel=fork)
正确的解决方法是什么?
完整示例http://coliru.stacked-crooked.com/a/737a0927ecd74458
P.S.我知道UDP不能使用连接,但是TCP和UDP在boost中有类似的接口,所以我认为我的问题不是在协议上。
1条答案
按热度按时间qnyhuwrf1#
你发布的工作,然后立即阻止它-这是毫无用处的定义。你总是可以直接调用你发布的函数。
这突出了问题:你在服务线程上阻塞 *,从而确保没有处理程序可以运行。这意味着
DoConnect
任务永远不会运行。相反,应该这样组织BRAC调用链,使得(完成)处理程序中没有任何东西阻塞。例如,我以前是如何处理相关的TCP问题的:
Coliru
更新:回顾
阅读你的full example有.很多问题。
boost::enable_shared_from_this
和std::shared_ptr
Connect
中,您立即调用async_resolve
,其想法是将that发布到strandasio::post
在那里是无用的。asio::post
是一个nrc初始化,这意味着它将总是立即返回(并且没有例外),使得循环也无用。asio::async_connect
代替手动枚举端点P.S.讽刺的是,我后来注意到,很明显你的例子是基于上面的TCP TLS客户端的(正如“错误的”
"syslog tls client: "
字符串所证明的那样)。正如你将在下面的摘要中看到的,它有 * 正是 * 你在删除它之前所需要的解决方案:)msg = std::string(msg)
从SendMessageAsync
lambda更改为msg = std::string(msg)
。这将创建UB,因为字符串视图可能会引用在运行bloc操作时不再可用的内存。这也是为什么m_outbox
包含std::string
而不是std::string_view
非常重要。async_send_to
分配给m_ep
,但m_ep
从未分配。因此,任何东西都不会被发送(更不用说到达了)。更像是:
修复你得到的所有这些东西:
Live On Coliru
一个当地的示范:
摘要
简而言之,promise only 用于最终用户在连接完成时进行同步。你不能阻止内线。
此外,有趣的是,所有这些都已经在启用TLS的示例中演示过了,您显然将其作为起点:
这在结构上与我们在所有修复之后最终得到的
DoConnect
相同: