Я использую тот же сокет на своем сервере 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 выдает исключение)
Возможно одновременное получение сокета 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
Класс позволяет сокету быть связанным с адресом, который уже используется. Тем не менее, я не думаю, что это применимое решение здесь, поскольку оно обычно используется:
TIME_WAIT
государство.Других решений пока нет …