我正在尝试使用BOOST :: ASIO在UDP中实现一些保持活动的服务,这些是常规步骤:
将保持活动状态发送到同一台计算机上的2个进程,它们正在使用不同的端口在同一ip上侦听。
循环向两者发送async_send_to,并且回调是使用回调F()调用async_receive_from的函数。 两者都引用相同的端点和数据缓冲区。
while循环,其中包含io_service.run_one()。
进程立即回复。
问题是,偶尔会在检查端点的端口(需要的情况)F()运行时获得2个不同的端口,或者得到的端口是相同端口的两倍。
似乎端点缓冲区(可能还有数据)已被后面的数据包覆盖。
我一直在考虑,因为我使用的是run_one(),因此应该对数据包进行逐一处理,并且不会被覆盖。
初始发送-
void GetInstancesHeartbeat(udp::endpoint &sender_endpoint)
{
int instanceIndex = 0;
for (; instanceIndex <= amountOfInstances ; instanceIndex++)
{
udp::endpoint endpoint = udp::endpoint(IP, Port+ instanceIndex);
m_instancesSocket->async_send_to(
boost::asio::buffer((char*)&(message),
sizeof(message)),endpoint,
boost::bind(&ClusterManager::handle_send_to_instance,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
sender_endpoint));
}
}
然后是处理程序-
void handle_send_to_instance(const boost::system::error_code& error, size_t
bytes_recvd, udp::endpoint &sender_endpoint)
{
m_instancesSocket->async_receive_from(
boost::asio::buffer(m_dataBuffer, m_maxLength), m_endpoint,
boost::bind(&ClusterManager::handle_receive_from_instance, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
sender_endpoint));
}
循环时-
while(true){
io_service.run_one();
}
句柄接收端口结果两次相同的位置-
void handle_receive_from_instance(const boost::system::error_code& error, size_t
bytes_recvd, udp::endpoint&sender_endpoint)
{
if (!error && bytes_recvd > 0)
{
int instancePort = m_endpoint.port();
} else {
//PRINT ERROR
}
}
答案 0 :(得分:0)
实际操作是异步的,因此无法确定何时写入端点引用。这就是异步调用的本质。
因此,您需要拥有的是每个异步调用的端点接收变量(您可以按实例索引存储它)。
还有许多其他可疑的地方:
message
的类型是什么?对于大多数类型,您只需要编写boost::asio::buffer(message)
(即可处理T []
,std::vector<T>
,array<T>
等)。当T
为char
或任何POD类型时,此方法有效。
如果message
实际上是某种类型的结构,请考虑使用单元素数组以避免进行强制转换:
POD message[1] = {pod};
s.async_send_to(boost::asio::buffer(message), udp::endpoint{{}, 6767}, [](boost::system::error_code ec, size_t transferred) {
std::cout << "Transferred: " << transferred << " (" << ec.message() << ")\n";
});
(在典型系统上发送12个字节)。
无论您做什么,都不要编写不安全的C样式强制转换(Why use static_cast<int>(x) instead of (int)x?)。
您有while(true) { io.run_one(); }
,这是一个无限循环。更好的书写方式是:while(io.run_one()) {}
但是,这基本上与io.run();
相同,但是正确性和效率较低(请参见https://www.boost.org/doc/libs/1_68_0/boost/asio/detail/impl/scheduler.ipp第138行),那么为什么不使用它呢?