LINUX.ORG.RU

Порядок пакетов в TCP и UDP

 


1

2

Добрый день. Подскажите пожалуйста, когда говорят о том, что «пакеты» UDP могут прийти не в том порядке или потеряться, что конкретно имеют в виду. Вот сделал я sendto() например например буфера в 3 000 байт. Тут понимается, что это буфер может быть разбить например на 2 UDP пакета которые могут прийти в порядке «первый», «второй», а могут в порядке «второй», «первый» или речь идет про то, что пакет UDP будет разбит например на 3 IP пакета по 1000 байт, которые на другом конце могут быть получены как первый, третий, второй.


в протоколе UDP нет алгоритма восстановления последовательности пакетов и даже нет подходящего поля в заголовке пакета.

в отличии от к примеру упомянутого TCP у которого прям в заголовке имеется 32 битное поле Sequence number, по которому можно отследить правильность последовательности пакетов, выпущенных отправителем, и восстановить на получателе, чем собственно и занимается TCP-протокол на приемнике и кой чем еще.

почитай мануал библиотеки, которая реализует sendto(). там должно быть все описано.

размер пакета ip определяется размером mtu. но можно и вручную уменьшить.
«разнообразие» прихода пакета определяется параметрами сети между передатчик и приемником.

pfg ★★★★★
()
Последнее исправление: pfg (всего исправлений: 1)
Ответ на: комментарий от pfg

Мне не очень понятна связь между send и пакетом TCP. Send буфера в 3000 байт это каким образом будет биться на пакеты? И какие гарантии на том конце? То что если например буфер был разбит на 3 пакета TCP в буфер заданный в recv они поступят строго в порядке отправки. Т.е. в цикле мы допустим получили первый пакет, второй был потерян, а третий пришел. Тогда ОС на принимающей стороне будет запрашивать у отдающей стороны второй пакет и вернет управление в recv только после получения второго пакета?

da17
() автор топика
Последнее исправление: da17 (всего исправлений: 1)

Вроде как 1 большой пакет разделится по mtu на части, но на другом конце склеится в один.
А если 2 udp пакета отправить, то второй раньше может прийти.

naKovoNapalBaran
()

Оба протокола строятся поверх IP, IP пакеты могут теряться и менять свой порядок, UDP - Ок, хер с ним, TCP - способ обойти эту проблему собственно.

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

Про смену порядка - сам бы послушал реальных кейсов.

Что точно знаю - если используется vpn, не будет ни того ни другого.

pon4ik ★★★★★
()

Нет, UDP-пакет это буфер целиком. Шлёт один раз 3000 байт - примешь их именно целиком как 3000 байт. Принять их двумя частями нельзя. И наоборот, если отправил два раза по 10 байт - примешь именно 2 раза по 10 байт, принять сразу 20 нельзя. То, что они где-то на низком уровне могут передаваться частями - от приложения всё так же прячется, то есть про это можешь не думать.

А насчёт порядка пакетов - дело вот в чём. Если ты сделаешь два send() то они могут приняться двумя recv-ами не в том порядке как их отправляли. Или вообще не дойти до получателя. Или продублироваться (сделал один send, а принялся он два раза - скорее всего одинаковых).

На практике нарушение порядка пакетов или их дублирование в современном инете это очень редкое событие. А вот потеряться пакет может легко, особенно в каком-нить мобильном подключении.

К TCP это всё неприменимо вообще, у него понятия «пакет» на уровне системных вызовов send() и recv() не существует. Просто байты один за другим идут и очередь соблюдается средствами ОС. То есть в TCP, в отличие от UDP, можно послать 2 раза по 10 байт и принять один раз 20, или наоборот послать 20 и принять 2 по 10.

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

Фрагментация UDP - это ненормальное явление и вообще самим протоколом не поддерживается (читать RFC768). Это датаграмный протокол и ты как сделал sendto(), так у тебя текущие данные из буфера пакетом и улетели. Другой вопрос, что если ты сделал пачку sendto() подряд, то на сети в силу разных причин они могут перемешаться и прийти не в том порядке, в котором улетели. Протокол не гарантирует доставку в том же порядке и исправление этой ошибки штатными средствами. Обычно возможность такой ситуации учитывается протоколами, которые работают поверх UDP (например, RTP содержит sequence number и timestamp, чтобы отрабатывать такие ситуации).

Единственный способ порезать UDP на куски - это фрагментация на L3 (IP fragmentation). https://notes.shichao.io/tcpv1/ch10/ Т.е. собирать надо на этом уровне.

TCP же - протокол потоковый и фрагментация - штатная фича (читать RFC793). Всё, что ты отправляешь, может чуть задержаться в буфере и в этом случае данные склеятся вместе (отправка потоком). Т.е. пара последовательных send()/sendto() на один сокет приведут к тому, что данные из двух буферов запросто улетят одим пакетом. Поэтому TCP может как фрагментироваться сам (L4 TCP fragmentation), либо на уровне L3 (IP fragmentation).

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

Всем спасибо. Вроде понял.

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

речь идет про то, что пакет UDP будет разбит например на 3 IP пакета по 1000 байт, которые на другом конце могут быть получены как первый, третий, второй

Именно так. TCP/IP стек на принимающем узле вообще не должен передавать фрагменты одной UDP датаграммы на уровень выше, т.е. на сетевом уровне стек должен будет принять все фрагменты IP пакета прежде чем извлечь из них данные и собрать в одну UDP датаграмму и передать на транспортный уровень. Иными словами, если Вы отправили массив в 3000 байт, то либо получите на принимающей стороне один пакет в 3000 байт, либо не дождётесь пакета вовсе.

Может быть есть такие реализации TCP/IP стека, в которых нужно руками фрагменты UDP датаграммы собирать на транспортном уровне, но я о таких не знаю.

Если интересно понять как фрагменты собираются на сетевом уровне, то RFC 791 и особенно раздел 2.3 Function Description, подраздел Fragmentation. В кратце, используются 4 поля в IP заголовке: Identification, Fragment Offset, Total Length и More Fragments флаг.

EDIT: Не туда ответил, извиняюсь. Хотел самому автору.

dsl
()
Последнее исправление: dsl (всего исправлений: 2)
Ответ на: комментарий от pfg

в протоколе UDP нет алгоритма восстановления последовательности пакетов и даже нет подходящего поля в заголовке пакета.

а вот как же фрагментирование пакета? Разве оно не является частичным восстановлением последовательности частей одного пакета?

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

фрагментация UDP пакета возможна на уровне IP-протокола. IP-драйвер приемника пакетов соберет каждый фрагмент IP-пакета, прежде чем его «распаковать» и передать его наверх UDP-драйверу, ну или дропнет все куски с данным индентификатором по таймауту.

фрагментация TCP пакета возможна и на уровне IP-протокола и на уровне TCP-протокола. зависит от умений/настроек фрагментатора.

pfg ★★★★★
()
Последнее исправление: pfg (всего исправлений: 2)
Ответ на: комментарий от pfg

А информация о том, что UPD пакет разбили на 2 IP пакета хранится где-то в заголовках IP? Я как-то бегло глянул на структуру IP пакета. Сходу не сообразил.

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

В IPv4 7 и 8 октеты.

В IPv6 через специальные флаги заголовков… но вообще IPv6 предпочитает его избегать, насколько я понимаю.

Scondo
()
Последнее исправление: Scondo (всего исправлений: 1)
Ответ на: комментарий от pfg

фрагментация TCP пакета возможна и на уровне IP-протокола и на уровне TCP-протокола.

Кмк, не очень уместно разговаривать о фрагментации на уровне TCP, хотя, в принципе, понятно о чём Вы.

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

но вообще IPv6 предпочитает его избегать

Этого предпочитают избегать все, вне зависимости от. Можно нарваться на серьёзные неприятности (потеря фрагмента => потеря всего пакета, усугубляется при bonding / multipath).

bugfixer ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.