Чи можна розділити пакети TCP і UDP на частини?

Чи можуть пакети TCP надходити до одержувача по частинах?

Наприклад, якщо я надсилаю 20 байт за допомогою протоколу TCP, чи можу я бути на 100% впевнений, що отримаю рівно 20 байтів одночасно, а не 10 байт, а потім ще 10 байт або близько того?

І те саме питання для протоколу UDP.
Я знаю, що UDP ненадійний, і пакети не можуть прийти взагалі або прийти в різному порядку, але як щодо одного пакета? Якщо він приходить, чи можу я бути впевнений, що це повний пакет, а не фрагмент?

36
Точка роз'яснення: називається сегментом TCP і дейтаграмою UDP. Вони не є пакетами. TCP = Segment, UDP = Datagram, IP = Packet, Ethernet = Frame, на всіх інших шарах (AFAIK) вони просто називаються PDU (Unit Data Unit).
додано Автор joeqwerty, джерело

5 Відповіді

Чи можуть пакети TCP надходити до одержувача по частинах?

Так. IP підтримує фрагментацію, хоча TCP взагалі намагається визначити MTU шляху і зберегти його пакети меншими, ніж з причин продуктивності. Фрагментація збільшує швидкість втрат дейтаграми катастрофічно. Якщо шлях має 10% втрати пакетів, фрагментація дейтаграми на два пакети робить втрату дейтаграми майже на 20%. (Якщо будь-який пакет втрачено, дейтаграма втрачається.)

Проте, вам не доведеться турбуватися про це, а також рівень TCP. Рівень IP повторно збирає пакети в цілі дейтаграми.

Наприклад: якщо я надсилаю 20 байт за протоколом TCP, чи можу я бути на 100% впевнений, що отримаю рівно 20 байтів одночасно, а не 10 байт, а потім ще 10 байт?

Ні, але це не має нічого спільного з пакетами. TCP - це, по суті, протокол байтів, який не зберігає межі повідомлень програми.

І це ж питання для протоколу UDP. Я знаю, що UDP ненадійний, і пакети не можуть прийти взагалі або прийти в іншому порядку,

Те ж саме стосується і TCP. Пакети є пакетами. Відмінність полягає в тому, що TCP має повторні спроби і переупорядкування, вбудовані в протокол, а UDP - не.

а що про 1 пакет? Якщо він приходить, чи можу я бути впевнений, що це повний пакет, а не фрагмент?

Ні, але це не ваша проблема. Протокол UDP обробляє збірку дейтаграм. Це частина його роботи. (Насправді протокол IP робить це для протоколу UDP, тому UDP робить це просто шляхом нанесення шарів поверх IP). буде показано повні дані.

29
додано
Можливо, варто роз'яснити останній біт для читачів-початківців: ви побачите повну інформацію для даної дейтаграми . Якщо будь-який з розділених пакетів втрачається, дейтаграма втрачається, і шар UDP ніколи не дізнається про нього. До тих пір, поки приймаються всі пакети в дейтаграмі, вони будуть зібрані на рівні IP, а потім передані до шару UDP. Це не виключає можливості відсутності "фрагментів" у потоці даних. Щоб не бути педантом, але коли я вивчав цю справу, я не мав різниці між IP-фрагментом і втратою UDP до 2-го або 3-го проходу через підручник.
додано Автор user83495, джерело

Ви не можете бути впевнені, що вони дійсно фізично прибувають відразу. Рівні зв'язків даних нижче TCP/UDP можуть розділити ваш пакет, якщо вони цього хочуть. Особливо, якщо ви надсилаєте дані через Інтернет або будь-які мережі поза вашим контролем, це важко передбачити.

Але неважливо, якщо дані надходять в один пакет або кілька пакетів на приймачі. ОС повинна абстрагувати конкатенацію цих пакетів, тому для вашого додатку вона все одно виглядає як все, що надійшло відразу. Таким чином, якщо ви не є хакером ядра, у більшості випадків вам не потрібно турбуватися, якщо ці дані передаються в одному або в багатьох пакетах.

Для UDP ОС також зробить деяку абстракцію, тому програма, яка отримує дані, не повинна знати, скільки пакетів дані були передані. Але відмінність від TCP полягає в тому, що немає ніякої гарантії, що дані дійсно надходять. Можливо також, що дані розбиваються на декілька пакетів, а деякі з них надходять, а деякі - ні. Для прийомної програми вона все одно виглядає як потік даних, незалежно від того, чи є вона повною чи ні.

19
додано
Чи не вживає драйвер мережевої карти повторне збирання пакетів, а не ядро?
додано Автор Sam Hartsfield, джерело
Існує певна надія, що він не буде розділений на крихітні корисні навантаження (близько 10 або 20 байтів має бути нормальним), оскільки для кожного хоп для IP-пакети на ipv4: не менше 68 байт (включаючи заголовки IP і не рахуючи заголовків нижнього рівня). див. першу таблицю в en.wikipedia.org/wiki/Maximum_transmission_unit . Відрізняється від 576 байтів мінімального розміру, необхідного від HOSTS (тобто, від початку або кінця передачі, не всіх посередницьких стрибків). І обережно: корисне навантаження ще менше (оскільки заголовки кожного шару займають певний простір).
додано Автор Olivier Dulac, джерело
@Hallucynogenyc: Якщо речі не змінилися, Інтернет-протокол призначений для того, щоб дозволити пакетам понад 576 байт розділитись у будь-якій точці подорожі, але не очікує нічого, крім останнього одержувача, щоб їх об'єднати. Я думаю, що ідея полягає в тому, що використання більших пакетів в більшості випадків було спробою зменшити накладні витрати; після того, як пакет був розділений в певний момент на шляху, накладні витрати вже були понесені, тому рекомбінація перед тим, як кінцевий одержувач не зможе нічого допомогти, і може зашкодити, якщо він повинен бути повторно розділений.
додано Автор supercat, джерело
Я вважаю, що в той час як будь-який пакет, що перевищує 576 байтів, може бути розділений, пакети, які нижче цього розміру, можуть не бути; Вбудовані системи, які не можуть працювати з розділеними пакетами, повинні уникати прохання нічого більшого.
додано Автор supercat, джерело
@ mauro.stettler: Я написав стек TCP на "голому металі" (написання коду, щоб розмовляти безпосередньо з числом чіпа мережевого інтерфейсу). Для апаратних засобів, які розмовляють з посиланням з 576-байтовим обмеженням на розділення довгих пакетів, це просто. Збірка пакетів є набагато складнішою, тим більше, що можна отримати шматки різних пакетів, перш ніж будь-яка з них буде отримана повністю.
додано Автор supercat, джерело

Приклади. Блоки суміжних символів відповідають викликам send ():

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

Всі відправлені дані отримуються в порядку, але не обов'язково в одних і тих же блоках.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

Дані не обов'язково в тому ж порядку, і не обов'язково отримуються взагалі, але повідомлення зберігаються у всій їх повноті.

13
додано

Наприклад: якщо я надсилаю 20 байтів, використовуючи протокол TCP, я можу бути на 100% впевнений, що я   отримає рівно 20 байтів одночасно, а не 10 байтів, потім ще 10   байтів або так?

Ні, TCP є протоколом потоку, він зберігає дані в порядку, але не групує його за повідомленням. З іншого боку, UDP орієнтований на повідомлення, але ненадійний. SCTP має найкраще з обох світів, але не є вбудованим, оскільки NAT переривають Інтернет.

5
додано

Існує певна впевненість, що якщо ви відправляєте 20 байтів на самому початку потоку TCP, воно не прийде як два 10-байтові частини. Це відбувається тому, що стек TCP не надсилатиме такі невеликі сегменти: існує мінімальний розмір MTU. Однак, якщо відправлення відбувається в середині потоку, всі ставки виключені. Можливо, ваш стек протоколу займає 10 байт даних, щоб заповнити сегмент і відправити його, а потім наступні десять байтів перейдуть в інший сегмент.

Стек вашого протоколу розбиває дані на фрагменти і поміщає їх у чергу. Розміри фрагментів базуються на тракті MTU. Якщо ви виконуєте операцію надсилання, і досі залишаються в черзі дані, стек протоколу зазвичай переглядає сегмент, який знаходиться в хвостовій частині черги, і перевіряють, чи є в цьому сегменті місце для додавання додаткових даних. Кімната міг бути на один байт, так що навіть двобайтове надсилання може бути розбито на два.

З іншого боку, сегментація даних означає, що може бути часткове читання. Операція прийому потенційно може прокинутися і отримати дані, коли надходить лише один сегмент. У широко використовуваних API сокетів, приймальний виклик може запитувати 20 байт, але він може повертатися з 10. Звичайно, на ньому може бути побудований буферизаційний шар, який блокується до отримання 20 байтів або розриву з'єднання. У світі POSIX цей API може бути стандартним потоком вводу-виводу: ви можете fdopen дескриптор сокету для отримання потоку FILE * , і ви можете використовувати fread , щоб заповнити буфер таким чином, що повний запит задовольняється стільки викликів read , скільки він приймає.

Дати UDP кадрують дані. Кожен виклик надсилання генерує дейтаграму (але див. Нижче про укупорки). Інша сторона отримує повну дейтаграму (і, в API сокету, вона повинна вказати буфер, достатній для його утримання, або дейтаграма буде усічена). Великі дейтаграми фрагментуються за допомогою фрагментації IP-адрес і повторно збираються прозоро до додатків. Якщо будь-який фрагмент відсутній, вся дейтаграма втрачається; неможливо прочитати часткові дані в цій ситуації.

Існують розширення інтерфейсу, що дозволяють декільком операціям вказувати одну дейтаграму. У Linux сокет може бути "закупорений" (запобігти відправці). В той час, як він закривається, письмові дані збираються в єдине ціле. Потім, коли сокет "відкупорюється", можна надіслати одну дейтаграму.

1
додано
це помилково: якщо ви надішлете паку з корисним навантаженням 10 або 20 байтів, це генерує 1 пакет, і (як я вже сказав вище), якщо використовується ipv4, він повинен, навіть при додаванні всіх заголовків інших шарів протоколу, підходити в межах 68 байт, таким чином забезпечуючи, щоб він проходив через всі переходи в 1 пакеті. Tcp стек не буде (як це натякнув у вашому 1-му абзаці) "чекати, поки mtu заповнений (тобто, додати кілька пакетів, щоб зробити правильно розміром один)", щоб відправити пакет! ... Ця поведінка порушить багато речей ( навіть якщо ці "фрагменти" надіслані від & до однієї пари хостів)
додано Автор Olivier Dulac, джерело
@OlivierDulac: Це неправильно. TCP, як правило, генерує пакети, які вони потребують, намагаючись оптимізувати використання мережі, тому 20 байт можуть опинитися в двох різних пакетах, як пояснює Kaz. Це можна контролювати за допомогою опції TCP_NODELAY , яка вимикає алгоритм Nagles, який розсилає байти до пакетів, якщо ваша програма потребує більш швидкої мережі TCP. Крім того, 68 байт жодним чином не є де-факто стандартом для довжини пакета: 1500 байт є більш звичайним значенням за замовчуванням (це дійсно залежить від мережі).
додано Автор jjmontes, джерело