LINUX.ORG.RU

Что будет, если из разных потоков для одного дескриптора вызывать poll и recvfrom?

Хм.. вы poll хотите в разных потоках вызывать?

Я вызываю и обрабатываю poll в главном потоке и в зависимости от events вызываю обработчик события нужного сокета. И все это в единственном главном потоке.

Использование poll/epoll/select позволяет избавиться от многопоточности.

Ой, я проглядел, что вы вызываете recvfrom, а не recv.

recfrom - это, обычно, работа по udp. Тут, как бы не нужны потоки, да и poll.

Висите на recvfrom и по получении данных вызываете обработчик привязанный к sockaddr_in.

poll для udp тоже можно внедрить, если вам нужно еще что-то обрабатывать, кроме ответа на поступающие запросы.

HighMan
()
Последнее исправление: HighMan (всего исправлений: 2)

poll-у вообще всё равно сколько раз и откуда его вызывать - вернёт одно и то же.

recvfrom - кто первый вызвал тот и поймает пришедшие данные

firkax ★★★★★
()

Вобщем-то проблема в том, что при высокой интенсивности сетевого трафика на приеме теряются udp пакеты. Идея читать сокет из нескольких потоков, конечно, совсем тупая. Но это то, что приходит первым в глову, как попытаться решить проблему простым способом. Можно, конечно, что-нибудь накостылить на тему rx-ring. Но хотелось все-таки прежде понять, что простые способы не работают.

Как вообще сейчас реализуется сетевой стек в современном ядре на много ядерных системах? Где там узкое место?

Пакеты, которые поступили в сетевуху, читает обработчик прерываний. Тут в любом случае работает в конкретный момент времени только одно ядро. Затем в очередь ставится врхняя половина обработчика прерываний/тасклет (или как это называется в современном ядре). Тут я так понимаю уже одновременно могут вести обрабтку несколько ядер. Или только одно? Юзерспейс процесс, читающий буфер сокета, насколько я помню, работает с этим всем асинхронно. Планировщик переключил задачу - буфер перетерся. Так?

Получается слаебое звено - процесс, читающий буфер сокета. Или надо буфер сокета делать огромного размера, что для обычного сокеат невозможно.

Короче, простыми средствами проблему не побороть. Так?

zloy_starper ★★★
() автор топика
Ответ на: комментарий от zloy_starper

Вобщем-то проблема в том, что при высокой интенсивности сетевого трафика на приеме теряются udp пакеты.

Есть уверенность что пакеты теряются из-за медленного чтения из сокета ? Реально SO_RXQ_OVFL прилетает ?

А то бывает что сетевое железо или драйвер не справляются и дропают пакеты

alx777 ★★
()
Ответ на: комментарий от zloy_starper

В UDP-стеке операционной системы есть достаточно большие буферы. Можешь их ещё больше увеличить. Пришедшие UDP-пакеты кладутся в этот буфер, прежде чем твоя программа их прочитает.

Иными словами если пакет дошёл до ОС и буферы настроены правильно, то пакет уже не потеряется.

В первую очередь тебе нужно убедиться, что твои пакеты теряются уже после прихода в ОС, а не до. Проще всего это проверить с помощью tcpdump.

vbr ★★★★
()
Ответ на: комментарий от zloy_starper

Можно, конечно, что-нибудь накостылить на тему rx-ring. Но хотелось все-таки прежде понять, что простые способы не работают.

То ли дело зачем-то читать сокет из нескольких потоков, вот это, видимо, просто.

Короче, простыми средствами проблему не побороть. Так?

Нет, придётся — только сразу не пугайся — сначала разбираться.

t184256 ★★★★★
()
Ответ на: комментарий от vbr

Да какие там большие буферы? 2к по умолчанию и 4к максимум. На два пакета хватит. До ядра пакеты все доходят. Смотрю в PREROUTING. Сколько отправили, столько ядро и приняло.

zloy_starper ★★★
() автор топика
Ответ на: комментарий от zloy_starper

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

anonymous
()
Ответ на: комментарий от zloy_starper

Если я не накосячил с recvmsg, то SO_RXQ_OVFL прилетает. Сразу, например, по 91 штуке, или больше. А бывает, что не прилетают.

Похоже, стек действительно закачивает в сокет больше, чем ты успеваешь прочитать

У recvmmsg параметер unsigned int vlen больше 1 ?

alx777 ★★
()
Ответ на: комментарий от alx777

Попробовал на скорую руку recvmmsg с параметром vlen 3. Практически всегда читает по 3 сообщения. Возможно мог бы и больше. Я так понимаю, такой вариант реализации должен сказаться в целом положительно на пропускную способность, так как делается меньше системных вызовов и переключений контекста. Но вряд ли решит кончательно проблему.

zloy_starper ★★★
() автор топика
Ответ на: комментарий от zloy_starper

Но вряд ли решит кончательно проблему.

Может и не решит. Остается только размер сокет буфера с vlen увеличивать и наблюдать что будет

Дальше надо смотреть, можно ли этот траффик делить на батчи и обрабатывать параллельно

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

Но лучше будет один читающий из сокета мастер-тред, распределяющий задачи между воркер-тредами

Если нет, то видимо «терпенью машины бывает предел» и пора апгрейдить железо

alx777 ★★
()