Подтвердить что ты не робот

Как контролировать свободное пространство UDP U Linux?

У меня есть приложение java для Linux, которое открывает UDP-сокет и ждет сообщений.

Через пару часов при большой нагрузке происходит потеря пакетов, т.е. пакеты принимаются ядром, но не моим приложением (мы видим потерянные пакеты в сниффере, мы видим, что UDP-пакеты потеряны в netstat, мы не см. эти пакеты в наших журналах приложений.)

Мы попытались увеличить буферы сокетов, но это не помогло - мы начали терять пакеты позже, но до этого.

Для отладки, я хочу знать, насколько полный буфер udp ОС, в любой момент. Googled, но ничего не нашел. Можете ли вы мне помочь?

P.S. Ребята, я знаю, что UDP ненадежен. Однако - мой компьютер получает все сообщения UDP, в то время как мое приложение не может использовать некоторые из них. Я хочу оптимизировать свое приложение до максимума, что причина вопроса. Благодарю.

4b9b3361

Ответ 1

Linux предоставляет файлы /proc/net/udp и /proc/net/udp6, в которых перечислены все открытые сокеты UDP (для IPv4 и IPv6, соответственно). В обоих из них столбцы tx_queue и rx_queue отображают исходящие и входящие очереди в байтах.

Если все работает должным образом, вы обычно не увидите ни одного значения, отличного от нуля, в этих двух столбцах: как только ваше приложение генерирует пакеты, они отправляются через сеть, и как только эти пакеты поступают из сети, ваша заявка будут просыпаться и получать их (вызов recv немедленно возвращается). Вы можете увидеть, что rx_queue идет вверх, если ваше приложение открыто для сокета, но не вызывает recv для получения данных или если оно недостаточно обрабатывает такие данные.

Ответ 2

UDP - это вполне жизнеспособный протокол. Это тот же самый старый случай для правильного инструмента для правильной работы!

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

Это может быть допущено для коротких всплесков. Очередь делает именно то, что она должна делать - очереди дейтаграмм до тех пор, пока вы не будете готовы. Но если средняя скорость прибытия регулярно вызывает отставание в очереди, пришло время перепроектировать вашу программу. Здесь есть два основных варианта: сократить прошедшее время обработки с помощью коварных методов программирования и/или многопоточную вашу программу. Можно также использовать балансировку нагрузки в нескольких экземплярах вашей программы.

Как уже упоминалось, в Linux вы можете проверить файловую систему proc, чтобы получить статус о том, что делает UDP. Например, если я cat /proc/net/udp node, я получаю что-то вроде этого:

$ cat /proc/net/udp   
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops             
  40: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 3466 2 ffff88013abc8340 0           
  67: 00000000:231D 00000000:0000 07 00000000:0001E4C8 00:00000000 00000000  1006        0 16940862 2 ffff88013abc9040 2237    
 122: 00000000:30D4 00000000:0000 07 00000000:00000000 00:00000000 00000000  1006        0 912865 2 ffff88013abc8d00 0         

Из этого я вижу, что сокет, принадлежащий идентификатору пользователя 1006, прослушивает порт 0x231D (8989) и что очередь приема составляет около 128 КБ. Поскольку 128 КБ является максимальным размером в моей системе, это говорит о том, что моя программа очень слаба, не отставая от прибывающих дейтаграмм. До сих пор было 2237 капель, что означает, что уровень UDP не может помещать в очередь сокетов еще несколько дейтаграмм и должен их отбрасывать.

Вы можете наблюдать за своим программным поведением с течением времени, например. с помощью:

watch -d 'cat /proc/net/udp|grep 00000000:231D'

Обратите внимание, что команда netstat делает примерно одно и то же: netstat -c --udp -an

Мое решение для моей программы weenie будет состоять из нескольких потоков.

Ура!

Ответ 3

rx_queue сообщит вам длину очереди в любой момент времени, но она не скажет вам, насколько полной была очередь, т.е. отметка с водой. Невозможно постоянно отслеживать это значение и не использовать его программно (см. Как получить количество данных в очереди для UDP-сокета?).

Единственный способ, которым я могу представить, как контролировать длину очереди, - это перемещение очереди в вашу собственную программу. Другими словами, запустите два потока: один читает сокет так быстро, как может, и выгружает дейтаграммы в вашу очередь; а другая - ваша программа, вытягивающая из этой очереди и обрабатывающая пакеты. Это, конечно, предполагает, что вы можете гарантировать, что каждый поток находится на отдельном CPU. Теперь вы можете отслеживать длину своей очереди и отслеживать отметку с водой.

Ответ 4

Процесс прост:

  • При желании приостановите процесс приложения.

  • Откройте сокет UDP. Вы можете вырвать его из работающего процесса, используя /proc/<PID>/fd, если это необходимо. Или вы можете добавить этот код к самому приложению и отправить ему сигнал - он, конечно же, будет иметь сокет.

  • Вызовите recvmsg в сжатом контуре как можно быстрее.

  • Подсчитайте, сколько пакетов/байтов вы получили.

Это отбросит любые датаграммы, буферизированные в настоящее время, но если это нарушит ваше приложение, ваше приложение уже было нарушено.