BOOST :: ASIO-UDP-端点被覆盖

时间:2018-12-06 19:06:56

标签: c++ sockets udp boost-asio

我正在尝试使用BOOST :: ASIO在UDP中实现一些保持活动的服务,这些是常规步骤:

  1. 将保持活动状态发送到同一台计算机上的2个进程,它们正在使用不同的端口在同一ip上侦听。

  2. 循环向两者发送async_send_to,并且回调是使用回调F()调用async_receive_from的函数。 两者都引用相同的端点和数据缓冲区。

  3. 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
                }
            }

1 个答案:

答案 0 :(得分:0)

实际操作是异步的,因此无法确定何时写入端点引用。这就是异步调用的本质。

因此,您需要拥有的是每个异步调用的端点接收变量(您可以按实例索引存储它)。

还有许多其他可疑的地方:

  • message的类型是什么?对于大多数类型,您只需要编写boost::asio::buffer(message)(即可处理T []std::vector<T>array<T>等)。当Tchar或任何POD类型时,此方法有效。

    如果message实际上是某种类型的结构,请考虑使用单元素数组以避免进行强制转换:

    Live On Coliru

    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行),那么为什么不使用它呢?