Используйте тот же сокет udp для асинхронного получения / отправки

Я использую тот же сокет на своем сервере udp для получения данных от клиентов на каком-либо порту, а позже после обработки запросов отвечаю клиентам, используя ip :: ud :: socket :: async_send_to

Прием также выполняется асинхронно с async_receive_from. Сокет использует тот же ioService (это тот же сокет в конце концов)
В документации четко не указано, можно ли в одно и то же время иметь один и тот же сокет udp, получать дейтаграммы от клиента A (асинхронно) и, возможно, одновременно отправлять другую дейтаграмму клиенту B (асинхронная отправка)
Я подозреваю, что это может привести к проблемам. В итоге я использовал тот же сокет для ответа, потому что не мог привязать другой сокет к тому же порту сервера при ответе на другой клиент.

Как я могу привязать другой сокет к тому же порту сервера?

РЕДАКТИРОВАТЬ. Я пытаюсь привязать второй сокет UDP к тому же порту UDP с:

socket(ioService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port))

Когда я делаю это в первый раз (привязка для сокета сервера «прием»), все в порядке, но при попытке создать другой сокет во второй раз, когда он сообщает об ошибке при привязке (asio выдает исключение)

5

Решение

Возможно одновременное получение сокета UDP от одной удаленной конечной точки и отправка другой удаленной конечной точке. Тем не менее, согласно Boost.Asio Темы и Boost.Asio документации, как правило, небезопасно совершать одновременные вызовы для одного объекта.

Таким образом, это безопасно:

 резьба_1 | thread_2
-------------------------------------- + ----------- ----------------------------
socket.async_receive_from (...); |
socket.async_send_to (...); |

и это безопасно

 резьба_1 | thread_2
-------------------------------------- + ----------- ----------------------------
socket.async_receive_from (...); |
| socket.async_send_to (...);

но это указано как небезопасное:

 резьба_1 | thread_2
-------------------------------------- + ----------- ----------------------------
socket.async_receive_from (...); | socket.async_send_to (...);
|

Имейте в виду, что некоторые функции, такие как boost::asio::async_read, площадь составная операция, и иметь дополнительные ограничения безопасности потока.


Если любое из следующего верно, то никакой дополнительной синхронизации не требуется, поскольку поток будет неявно синхронным:

  • Все вызовы сокетов происходят внутри обработчиков, и io_service::run() вызывается только из одного потока.
  • async_receive_from а также async_send_to вызываются только в пределах одной и той же цепочки асинхронных операций. Например, ReadHandler перешел к async_receive_from Запускает async_send_toи WriteHandler перешел к async_send_to Запускает async_receive_from,

    void read()
    {
    socket.async_receive_from( ..., handle_read );  --.
    }                                                   |
    .-----------------------------------------------'
    |      .----------------------------------------.
    V      V                                        |
    void handle_read( ... )                             |
    {                                                   |
    socket.async_send_to( ..., handle_write );  --.   |
    }                                               |   |
    .-------------------------------------------'   |
    |                                               |
    V                                               |
    void handle_write( ... )                            |
    {                                                   |
    socket.async_receive_from( ..., handle_read );  --'
    }
    

С другой стороны, если есть несколько потоков, потенциально выполняющих одновременные вызовы к сокету, тогда должна произойти синхронизация. Рассмотрите возможность выполнения синхронизации, либо вызывая функции и обработчики через повышение :: ASIO :: io_service :: нитка, или используя другие механизмы синхронизации, такие как Boost.Thread’s мьютекс.


В дополнение к безопасности потоков необходимо учитывать управление временем жизни объектов. Если серверу необходимо обрабатывать несколько запросов одновременно, будьте осторожны с владельцем buffer а также endpoint для каждого request-> процессно> ответ цепь. в async_receive_fromДокументация, вызывающая сторона сохраняет право собственности на оба буфер а также конечная точка. Таким образом, управлять жизненным циклом объектов с помощью повышение :: shared_ptr. В противном случае, если цепочка достаточно быстрая, чтобы параллельные цепочки не требовались, это упрощает управление, позволяя буфер а также конечная точка использоваться по запросу.


Наконец, socket_base::reuse_address Класс позволяет сокету быть связанным с адресом, который уже используется. Тем не менее, я не думаю, что это применимое решение здесь, поскольку оно обычно используется:

  • TCP разрешает процессу перезапускать и прослушивать один и тот же порт, даже если порт находится в TIME_WAIT государство.
  • Для UDP, чтобы разрешить нескольким процессам связываться с одним и тем же портом, позволяя каждому процессу получать и передавать через многоадресную рассылку.
14

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]