якщо пакет TCP отримав часткове підтвердження, як буде реагувати механізм повторної передачі?


12

якщо tcp-клієнт надсилає пакет із порядковим номером від 10000 до 20000 на сервер tcp. tcp відповість ACK з seq_ack 20001.

якщо я перехоплюю пакет TCP від ​​клієнта і розділяю пакет на 2 сегменти tcp, один із seq від 10000 до 15000, а другий з seq від 15001 до 20000. А потім ці 2 сегменти TCP надсилаються на сервер TCP. Припустимо, що другий відрізок втрачено на шляху. Сервер TCP відповість ACK з seq_ack 15001.

Тепер, оскільки клієнт TCP надсилає інтегральний пакет з послідовністю 10000 до 20000, але він отримує ACK з 15001, з точки зору клієнта, це дивно. Як він відреагує? Теоретично, клієнт повинен повторно передати байти від seq 15001 до 20000, а саме клієнт передасть нові пакети від seq 15001. Але як щодо практики, що стосується впровадження стека TCP, це така ж, як і в теорії?

Я думаю, що в буфері відправлення TCP, коли відправляється сегмент tcp, сегмент залишається там, поки не буде ACK. Коли ACK надходить, ці байти для сегмента очищаються від буфера. У буфері відправлення є вказівник, коли ACK приходить, вказівник вказує на місце, де відповідає ack_seq. Очищені байти, розташовані нижче ack_seq. Таким чином, весь сегмент не потрібно повторно передавати?

Відповіді:


8

Це називається вибірковим підтвердженням і вже включено в специфікацію TCP, визначену в RFC 2018 . Це дозволило б клієнту дійсно повторно відправляти лише байти 15001 до 20000 (оскільки вони знаходяться в різних пакетах / сегментах, якби ви розділили їх, як ви говорите), але що цікавіше, це навіть дозволяє підтвердження поза замовленням.

Від RFC 2018:

При отриманні ACK, що містить опцію SACK, відправник даних ДОЛЖЕН би записати селективне підтвердження для подальшого використання. Передбачається, що у відправника даних є черга на повторну передачу, яка містить сегменти, які були передані, але ще не підтверджені, у порядку послідовності номерів.

Підтримка SACKбуде НЕ потрібно специфікацією TCP. Якщо або клієнт, або сервер не підтримували селективне підтвердження, насправді всі байти від 10000 до 20000 повинні були бути повторно передані.

У реалізації стека TCP це те саме, що і в теорії?

Зазвичай SACK це підтримується, оскільки підвищення продуктивності, ефективності та затримки є значним - особливо в такій мережі, як Інтернет.

Насправді, ці припущення мають бути справдими, навіть якщо ви вручну маніпулюєте пакетами, як ви заявили. Згідно з RFC 793 , як мінімум, все вікно даних доведеться повторно передавати, але приймач дійсно знає, що отримані дані є принаймні дійсними . Детальніше про впровадження, Розділ 3.3 - Послідовні номери з RFC 793.

Ознайомлення з усім процесом як із підтримкою вибіркового підтвердження, так і без неї, див. Цю статтю (яка включає деякі дуже корисні діаграми).


мені це трохи дивно, тому що TCP - потоковий, байт-орієнтований протокол. Чому слід повторно передавати весь сегмент? Мені здається, що TCP без SAKC є протокольним потоковим потоковим протоколом, але TCP з Sack реально орієнтований на байт. Я думаю, що RFC не детально розглядає це питання.
містерії

як стек TCP управляє своїм буфером відправки, чи це те саме, що я написав в оновленому запитанні.
містерії

@misteryes У цій статті окреслюється процес (з чудовими діаграмами теж!).
Прорив

У посиланні, яке ви рекомендували, видається, що автор все ще обговорює проблему орієнтованим на сегмент, а не реально на байт. Чи не так?
містерії

1
Я знав SACK, перш ніж розмістити це запитання. На самому початку я не думаю, що SACK має щось спільне з цим питанням. На мою думку, якщо TCP орієнтований не на байт, а на сегменти, то SACK також повинен бути таким же. Різниця між включеним SACK і відключеним SACK полягає в тому, що при SACK TCP дозволяє відкрити отвір послідовності в ack_seq. Але я подумав, що отвір послідовності відповідає сегменту. тоді як, за вашою приказою, отвір може бути половиною / частиною відрізка.
містерії

3

Розміри сегментів можуть (і можуть) змінюватися протягом життя з'єднання. На щастя, TCP не потребує запису розміру сегмента, з яким окремі пакети були відправлені раніше. Тому він зробить наступне:

  1. Щоразу, коли ACK надходить, пересуньте вказівник на перший непідтверджений байт відповідно та відкиньте будь-який тепер непотрібний буфер.
  2. Коли виникне потреба у повторній передачі (Швидкий Retransmit або Timeout; НЕ одразу після отримання першого ACK!), Він буде повторно відправлений у поточному розмірі сегмента, починаючи від вказівника до першого непідтвердженого байта.

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

Дозвольте пояснити:

Чи використовує TCP байти чи сегменти? Програмі TCP відкриває інтерфейс потоку байтів. Також усі поля заголовка та внутрішні змінні знаходяться в байтах. Однак для передачі інформації TCP з’єднує їх по сегментах, оскільки відправлення байтів один за одним було б досить марно :-). Використання лічильників байтів скрізь має перевагу в тому, що розмір сегмента не повинен залишатися постійним протягом усього часу з'єднання:

  • Вводяться параметри, наприклад, копіювання SACK під час повторної передачі (реальні реалізації зустрічаються з цим рідко, якщо взагалі є)
  • MTU Path змінюється, наприклад, одна ланка вздовж шляху змінюється на нижчу MTU або піднімається посилання MTU вузького місця. Це відбувається, коли встановлюються тунелі (VPN, PPPoE) або протокол маршрутизації вибирає інше-MTU-посилання. Це відбувається в IPv4 з набором Don't Fragment (справедливо для більшості сучасних TCP); завжди в TCPv6).

BTW: SACK - це не відповідь, оскільки приймач (як правило) використовує SACK лише тоді, коли він розпізнає дірку в потоці байтів (тобто, якщо пакет загубився, але наступний пакет прийшов).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.