Обнаружение переполнения буфера сокета UDP

#c #boost #cross-platform #udp

#c #повышение #кроссплатформенный #udp

Вопрос:

Я разрабатываю кроссплатформенный инструмент, который захватывает несколько потоков udp с различной скоростью передачи данных. boost::asio используется для создания сети. Есть ли какой-либо способ обнаружить ситуацию, когда буфер udp был заполнен и могла произойти потеря данных в сокете? Единственный способ, который я вижу сейчас, — это чтение /proc/%pid% / net / udp, но это не применимо для Windows, как вы знаете :). Также я хотел бы использовать для этого функции boost, если это возможно.

Комментарии:

1. Это не принесло бы вам многого. Ваш локальный буфер является лишь одним из многих мест, где эти UDP-пакеты могли быть сброшены по маршруту.

2. Спасибо, я знаю, что такое udp. Но потоки огромны (десятки / сотни Мбит / с), и обработка сложна. Поэтому было бы неплохо обнаружить ситуацию, когда ресурсов недостаточно для обработки такого объема данных.

Ответ №1:

Если вам нужна эта возможность, вы должны закодировать ее в протокол, который вы используете. UDP не способен сделать это сам. Например, вы могли бы поместить порядковый номер в каждую дейтаграмму. Отсутствующие дейтаграммы будут соответствовать отсутствующим порядковым номерам.

Комментарии:

1. О, было бы неплохо использовать это решение, но я не могу вносить изменения в протокол.

2. Проверка, чтобы увидеть, предоставляет ли протокол какой-либо другой способ. Трудно представить, как протокол был бы полезен, если бы он не предоставлял способа оценить, удалялись ли данные.

Ответ №2:

Я только что столкнулся с той же проблемой (хотя для меня специфичен для Linux), и, несмотря на то, что вопрос старый, я мог бы также документировать свои выводы для других.

Насколько я знаю, для этого нет переносимого способа, и Boost напрямую ничего не поддерживает.

Тем не менее, есть несколько способов сделать это в зависимости от платформы. В Linux это можно сделать, установив параметр сокета SO_RXQ_OVFL, а затем получая ответы с помощью recvmsg(). Хотя это плохо документировано, но вам может помочьhttp://lists.openwall.net/netdev/2009/10/09/75.

Один из способов избежать этого в первую очередь — увеличить буферы приема (я предполагаю, что вы уже исследовали это, но включили его для полноты). Параметры SO_RCVBUF кажутся довольно хорошо поддерживаемыми кроссплатформенными. http://pubs.opengroup.org/onlinepubs/7908799/xns/setsockopt.html http://msdn.microsoft.com/en-us/library/windows/hardware/ff570832 (v = против 85).aspx OS: es устанавливает для этого верхний предел, который администратору, возможно, придется увеличить. В Linux, т.е. его можно увеличить с помощью /proc/sys/net /core/rmem_max.

Наконец, одним из способов для вашего приложения оценить его «нагрузку», которая при больших входных буферах может служить для раннего обнаружения перегрузки, может заключаться в том, чтобы ввести временную метку до и после асинхронных операций. В псевдокоде (не с поддержкой boost::async-adapted):

 work_time = 0
idle_time = 0

b = clock.now()
while running:
  a = clock.now()
  work_time  = a-b
  data = wait_for_input()
  b = clock.now()
  idle_time  = b-a
  process(data)
  

Затем примерно каждую секунду вы можете проверять и сбрасывать work_time / (work_time idle_time) . Если оно приближается к 1, вы знаете, что приближаетесь к проблеме, и можете отправить предупреждение или предпринять другие действия.

Комментарии:

1. Спасибо за упоминание SO_RXQ_OVFL. Просто чтобы добавить, здесь есть полезный пример его использования: github.com/linux-can/can-utils/blob/master/candump.c