Как разделить полученные с помощью boost asio udp сокеты единые датаграммы

Я сделал свой UDP-сервер и клиент с помощью udp-сокетов boost :: asio. Все выглядело хорошо, пока я не начал отправлять новые датаграммы. Они правильно передаются от клиента к серверу. Но в моем буфере они объединены в одно сообщение.

я использую

udp::socket::async_receive с std::array<char, 1 << 18 > буфером

для выполнения асинхронного запроса. И получать данные через обратный вызов

void on_receive(const error_code& code, size_t bytes_transferred)

Если я отправляю данные слишком часто (каждые 10 миллисекунд), я получаю несколько датаграмм одновременно в свой буфер с обратным вызовом выше. Вопрос в том, как их разделить? Примечание. Мои датаграммы UDP имеют переменную длину. Я не хочу использовать дополнительный заголовок с размером, потому что это сделает мой код бесполезным для сторонних датаграмм.


person valery_l    schedule 20.07.2012    source источник
comment
Используйте в своем on_receive сообщении предоставленную пользователем функцию обратного вызова, которая обрабатывает все включенные сообщения в один полученный пакет.   -  person Chad    schedule 23.07.2012
comment
Конечно, его можно найти здесь: udp2tcp_tunnel. Он в процессе - еще маленький сервер для пинг-понга (отправка по TCP от клиента, получение того же тестового сообщения от сервера по UDP). Мне кажется, я нашел проблему. Если я отправлю несколько буферов в буферной последовательности с помощью 'basic_datagram_socket :: async_send_to (buffer_sequence, handler)', это будет одна дейтаграмма (а не одна дейтаграмма для каждого буфера).   -  person valery_l    schedule 23.07.2012
comment
Вы пробовали buf_.clear() после получения каждой дейтаграммы?   -  person Nikolai Fetissov    schedule 23.07.2012
comment
@ Николай, нет. Но предположим, что это не решение, потому что в моем обработчике приема есть значение «bytes_transferred», равное размеру нескольких датаграмм вместе. Я решил проблему, отправив за один раз только один буфер с помощью 'basic_datagram_socket :: async_send_to', при этом по-прежнему отправив несколько буферов с помощью 'async_write' для сокета TCP. Может есть какое-нибудь решение получше?   -  person valery_l    schedule 23.07.2012
comment
Похоже, это правильное решение. Одна отправка UDP отправляет одну дейтаграмму (возможно, со сбором ввода-вывода в случае мультибуфера). Способ обойти это в Linux - sendmmsg (man7.org/linux /man-pages/man2/sendmmsg.2.html), который, я сомневаюсь, поддерживается asio.   -  person Nikolai Fetissov    schedule 23.07.2012
comment
@Nikolai, спасибо за помощь. Не нашел ничего похожего на sendmmsg для сокета udp в asio. К сожалению, мое решение могло привести к проблеме, когда частота небольших сообщений будет слишком высокой.   -  person valery_l    schedule 23.07.2012
comment
Здесь есть два варианта: а) отказаться от asio для случая UDP и прибегнуть к программированию собственных сокетов - это может нарушить вашу модель; и б) упаковать больше в одну дейтаграмму, скажем, все, что вы получили за один цикл опроса - это означает добавление небольшого заголовка (ов), такого как количество / длина сообщений приложения в пакете.   -  person Nikolai Fetissov    schedule 23.07.2012


Ответы (1)


Я считаю, что это ограничение того, как boost :: asio обрабатывает потоки данных без сохранения состояния. Я заметил точно такое же поведение при использовании boost :: asio для последовательного интерфейса. Когда я отправлял пакеты с относительно большими промежутками между ними, я получал каждый из них в виде отдельного обратного вызова. По мере того, как размер пакета увеличивался и, следовательно, промежуток между пакетами уменьшался, он достиг стадии, когда он выполнял обратный вызов только тогда, когда буфер был заполнен, а не после получения одного пакета.

Если вы точно знаете размер ожидаемых датаграмм, то ваше решение по ограничению размера входного буфера является совершенно разумным, поскольку вы заранее знаете, насколько большим должен быть буфер.

Если ваша перегрузка возникает из-за передачи нескольких разных типов пакетов, поэтому вы не можете предварительно выделить буфер правильного размера, тогда вы потенциально можете создать разные сокеты на разных портах для каждого типа транзакции. Это немного более "хакерский", но учитывая практически неограниченный характер доступности эфемерного порта, если вы не используете 20 000 различных типов пакетов, которые, вероятно, также вам помогут.

person OcularProgrammer    schedule 21.08.2013