Коллеги, привет.
Подскажите, пожалуйста, можно ли из нескольких потоков читать данные из одного и того же UDP-сокета?
Будут ли данные потеряны и/или повреждены?
И какую документацию можно на эту тему почитать?
Я смог нагуглить, что recv/recvfrom являются потокобезопасными, т.е. их можно вызывать одновременно.
Но что будет с данными, которые они читают?
Не будет ли так, что один кусок датаграммы уйдет в один поток, а другой кусок — в другой поток?
Здравствуйте, DTF, Вы писали:
DTF>И какую документацию можно на эту тему почитать?
Про сокеты...
DTF>Но что будет с данными, которые они читают?
Вернется очередная датаграмма (если влезет во входной буфер)
DTF>Не будет ли так, что один кусок датаграммы уйдет в один поток, а другой кусок — в другой поток?
Протокол UDP не бьет датаграммы на части.
Здравствуйте, Nikolay_Ch, Вы писали:
N_C>Про сокеты...
Это понятно... но в статьях, которые я нагуглил, про это подробно не расписано.
МОжно ссылку на конкретное место в документации?
N_C>Вернется очередная датаграмма (если влезет во входной буфер)
А если не влезет? Остаток будет отброшен или попадет в другой recv?
N_C>Протокол UDP не бьет датаграммы на части.
Так и вопрос-то не про сетевой протокол UDP, а про API, через который данные читаются.
DTF>Не будет ли так, что один кусок датаграммы уйдет в один поток, а другой кусок — в другой поток?
да так и будет
куда читаете туда и уйдет
какой вообще смысл использовать recvfrom на одном сокете с разных потоков ?
как вы потом те данные клеить будете ?
вообще нужно уточнять винда или юникс, у них все по разному устроено
DTF>>Не будет ли так, что один кусок датаграммы уйдет в один поток, а другой кусок — в другой поток? R>да так и будет
Не вводите в заблуждение. Датаграммы не бьются на части.
Здравствуйте, DTF, Вы писали:
N_C>>Про сокеты... DTF>Это понятно... но в статьях, которые я нагуглил, про это подробно не расписано. DTF>МОжно ссылку на конкретное место в документации?
Я привык ориентироваться на MSDN... Там есть обширная глава Windows Sockets...
N_C>>Вернется очередная датаграмма (если влезет во входной буфер) DTF>А если не влезет? Остаток будет отброшен или попадет в другой recv?
В никсах не силен, а в Windows по умолчанию копируется максимально возможное количество, остальное отбрасывается, т.е. теряется навсегда. Понятное дело, что при этом генерится ошибка — переполнение буфера.
N_C>>Протокол UDP не бьет датаграммы на части. DTF>Так и вопрос-то не про сетевой протокол UDP, а про API, через который данные читаются.
Есть две парадигмы — датаграммы и потоки. API сокетов работает в этих парадигмах.
N_C>>Не вводите в заблуждение. Датаграммы не бьются на части. R>нет никакой гарантии что recvfrom вернет вам 100% полный кусок
Есть. Если датаграмма не получена полностью, recvfrom не вернет вам ничего. В этом и отличие датаграмм-парадигмы от потоков TCP.
R>причин может +10500 R>внутри ОС дейтаграмма бьется на мелкие буферы mbuf
Э... UDP-датаграмма бьется на IP-датаграммы, которые, в свою очередь, бьются на Ethernet-фреймы... TCP, кстати, тоже бьется.
И что, это как-то меняет парадигму датаграмм и потоков?
изначально моя мысль была другая
если UDP используется для отправки какого то пакетированного потока
то
1) ловля пакетов recvfrom с разных потоков и закидывания в общую очередь (поток то отправлен один) — никак не ускорит
2) буфер для ловли может быть меньше чем самый большой кусок отправленного пакета,
и тогда мы ловим меньший кусок, выходим с recvfrom И ? другим потоком ловим оставшуюся часть ?
в ту же тему куда свернули вы, допустим максимальный размер который ловим в юзермоде 65536 байт, почти 65 кил
mbuf если я не ошибаюсь 4096 байт, 4 килобайта
пришедшая дейтаграмма в 65536 байт,
и случайно не хватившей места в буфере (начала кластеры аллочить по 4к и не хватило, ну да всяко бывает в ОС)
вряд ли будет мочиться уже на принятой стороне (лишь предполагаю)
вариантов два, 1) замочит отдав юзеру ошибку(коварная ОС)
2) не мочить а отдать юзеру столько сколько пришло (дружелюбная ОС)
лезть смотреть хотя бы в линукс о том как вообще ведут себя в таких ситуациях ОС, не хочу
в никсах они не iocp
а в винде posix лежит сверху iocp насколько я знаю, т.е. емуляция
автор не уточнил какая ос и какие функции
но с IOCP есть мысли что будет работать все по другому, ну т.е. там винда сама все по потокам раскидает
вообще еще в никсах есть recvmsg, так что может есть смысл с ими поиграться для ловли большего числа буферов
R>изначально моя мысль была другая R>если UDP используется для отправки какого то пакетированного потока R>то R>1) ловля пакетов recvfrom с разных потоков и закидывания в общую очередь (поток то отправлен один) — никак не ускорит R>2) буфер для ловли может быть меньше чем самый большой кусок отправленного пакета, R> и тогда мы ловим меньший кусок, выходим с recvfrom И ? другим потоком ловим оставшуюся часть ?
Мы не можем ловить меньшую или большую часть... Мы выбираем очередную датаграмму из пришедших.
Если она не влезает в буфер то мы теряем датаграмму полностью. Никакая Ось не будет выбирать из входящих датаграмм именно ту, что влезет в переданный recvfrom буфер.
R>в ту же тему куда свернули вы, допустим максимальный размер который ловим в юзермоде 65536 байт, почти 65 кил R>mbuf если я не ошибаюсь 4096 байт, 4 килобайта
Да не имеет отношение этот mbuf к буферу хранящему входящие датаграммы сокета...
R>пришедшая дейтаграмма в 65536 байт, R>и случайно не хватившей места в буфере (начала кластеры аллочить по 4к и не хватило, ну да всяко бывает в ОС) R>вряд ли будет мочиться уже на принятой стороне (лишь предполагаю) R>вариантов два, 1) замочит отдав юзеру ошибку(коварная ОС) R>2) не мочить а отдать юзеру столько сколько пришло (дружелюбная ОС)
R>лезть смотреть хотя бы в линукс о том как вообще ведут себя в таких ситуациях ОС, не хочу
А стоит Потому, что Вы описали варианты мифического поведения, которого нет в POSIX-сокетах. По крайней мере я о таком поведении никогда не слышал. Может и есть какая-то опция, которая заставляет сокеты так работать, но по умолчанию они работаю по другому.
Если датаграмма не принята полностью на клиенте (т.е. она не заложена во входящий буфер сокета), recvfrom блокирует исполнение программы (если его не перевели в неблокирующий режим). И не будет ни первого ни второго варианта. Первого — клиент не получает ошибки о том, что какая-то датаграмма не влезла в буфер сокета из входящей сети. Второго — потому, что так UDP-сокеты не работают.
R>в никсах они не iocp R>а в винде posix лежит сверху iocp насколько я знаю, т.е. емуляция
А какая разница? recvfrom где где, а на Винде уж точно работает именно так, как я написал.
R>автор не уточнил какая ос и какие функции R>но с IOCP есть мысли что будет работать все по другому, ну т.е. там винда сама все по потокам раскидает
recvfrom — это POSIX вроде как...
R>вообще еще в никсах есть recvmsg, так что может есть смысл с ими поиграться для ловли большего числа буферов
Каких буферов, извините? Есть входящий буфер сокета и туда складываются датаграммы. Их не одна, не две а много...
Здравствуйте, reversecode, Вы писали:
DTF>>Не будет ли так, что один кусок датаграммы уйдет в один поток, а другой кусок — в другой поток? R>да так и будет
Не так не будет. Вы вводите человека в заблуждение.
См.: IEEE Std 1003.1, 2004 Edition: For message-based sockets, such as SOCK_RAW, SOCK_DGRAM, and SOCK_SEQPACKET, the entire message shall be read in a single operation. man 2 socket: SOCK_DGRAM and SOCK_RAW sockets allow sending of datagrams to correspondents named in sendto(2) calls. Datagrams are generally received with recvfrom(2), which returns the next datagram along with the address of its sender. MSDN: recvfrom function: The recvfrom function receives a datagram and stores the source address.
И дальнейшее апеллирование к mbuf в корне неверно. R>куда читаете туда и уйдет R>какой вообще смысл использовать recvfrom на одном сокете с разных потоков ? R>как вы потом те данные клеить будете ?
Если дейтаграмы можно обрабатывать параллельно, то всё это приемлемо масштабируется.
R>вообще нужно уточнять винда или юникс, у них все по разному устроено
Логика работы того API что скопировали у BSD у них отличается разве что в shutdown/close. Всё остальное поразительно идентично.
N_C>Мы не можем ловить меньшую или большую часть... Мы выбираем очередную датаграмму из пришедших. N_C>Если она не влезает в буфер то мы теряем датаграмму полностью. Никакая Ось не будет выбирать из входящих датаграмм именно ту, что влезет в переданный recvfrom буфер.
ок. заставили старичка залезть в гугл
гугл говорит что если дейтаграмма больше чем буфер, то в буфер попадает то что влезает, остальное отбрасывается
N_C>А стоит Потому, что Вы описали варианты мифического поведения, которого нет в POSIX-сокетах. По крайней мере я о таком поведении никогда не слышал. Может и есть какая-то опция, которая заставляет сокеты так работать, но по умолчанию они работаю по другому.
N_C>Если датаграмма не принята полностью на клиенте (т.е. она не заложена во входящий буфер сокета), recvfrom блокирует исполнение программы (если его не перевели в неблокирующий режим). И не будет ни первого ни второго варианта. Первого — клиент не получает ошибки о том, что какая-то датаграмма не влезла в буфер сокета из входящей сети. Второго — потому, что так UDP-сокеты не работают.
мочить дейтаграмму уже на клиенте из за того что проблемы с памятью не комильфо
вот лень мне лезть в ядра юникса что бы увидеть как они поступают
Здравствуйте, reversecode, Вы писали:
R>нет никакой гарантии что recvfrom вернет вам 100% полный кусок R>причин может +10500 R>внутри ОС дейтаграмма бьется на мелкие буферы mbuf
Это внутренние проблемы ОС. recvfrom() из датаграмного сокета делает одно из двух: либо вычитывает одну целую датаграмму, либо возвращает ошибку. Датаграмма никогда не бьется между двумя последовательными recvfrom()
Здравствуйте, reversecode, Вы писали:
N_C>>Мы не можем ловить меньшую или большую часть... Мы выбираем очередную датаграмму из пришедших. N_C>>Если она не влезает в буфер то мы теряем датаграмму полностью. Никакая Ось не будет выбирать из входящих датаграмм именно ту, что влезет в переданный recvfrom буфер.
R>ок. заставили старичка залезть в гугл R>гугл говорит что если дейтаграмма больше чем буфер, то в буфер попадает то что влезает, остальное отбрасывается
Ну так а я о чем? Только это буфер, который Вы передали в recvfrom...
По-моему Вы путаетесь в буферах... А их там много — на каждом уровне свои. Ethernet, IP, UDP, SOCKET...
И на каждом уровне датаграмма (или что-то иное) своя. И пока на очередном уровне не будет принята полностью датаграмма вышележащего уровня она не поднимается вверх.