BOOST :: ASIO - UDP - конечная точка перезаписывается - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь внедрить некоторую службу поддержки активности в UDP с помощью BOOST :: ASIO, это общие шаги:

  1. Отправка сообщений активности двум процессам на одной машинеони прослушивают один и тот же ip с другим портом.

  2. Цикл для отправки async_send_to обоим, и обратный вызов - это функция, которая вызывает async_receive_from с обратным вызовом F ().Оба ссылаются на одну и ту же конечную точку и буферы данных.

  3. в то время как цикл с io_service.run_one () внутри.

Процессы отвечают немедленно.

Проблема в том, что время от времени я либо получаю 2 разных порта, когда проверяю порты конечных точек (требуемый случай) F (), либо получаю дважды один и тот же порт.

Этопохоже, что буфер конечной точки (и, вероятно, данные) перезаписывается последним пакетом.

Я думал, так как я использую 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 голосов
/ 07 декабря 2018

Фактические операции являются асинхронными, поэтому неизвестно, когда будет записана ссылка на конечную точку.Такова природа асинхронных вызовов.

Итак, вам нужна конечная точка, принимающая переменную для каждого асинхронного вызова (вы можете сохранить ее для индекса экземпляра).

Существует ряд другихдействительно подозрительные биты:

  • что за тип message?Для большинства типов вы пишете просто boost::asio::buffer(message) (что относится к T [], std::vector<T>, array<T> и т. Д.).Это работает, когда T равен char или любому типу 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 ( Зачем использовать static_cast (x) вместо (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), так почему бы не использовать его?

...