Навіщо нам потрібно тристороння рукостискання? Чому б не просто двосторонній?


124

Тристоронній посібник TCP працює так:

Client ------SYN-----> Server
Client <---ACK/SYN---- Server
Client ------ACK-----> Server

Чому б не просто це?

Client ------SYN-----> Server
Client <-----ACK------ Server

24
Навіщо нам навіть потрібне рукостискання? Чому повідомлення не може бути надіслане з першим пакетом?
Мехрдад

4
Якщо ви хочете пропустити рукостискання, можете скористатися UDP.
OzNetNerd

5
@Mehrdad, якщо у вас є власне запитання, будь ласка, скористайтеся посиланням Задати питання вгорі сторінки, щоб опублікувати своє.
YLearn

40
@YLearn: Вибачте, це насправді не моє власне питання, а скоріше було мотивувати читачів давати відповіді, які копають трохи глибше, ніж те, що буквально зазначено у питанні.
Мехрдад

3
Не забувайте про TCP Fast Open (RFC 7413)
Альнітак

Відповіді:


158

Розбийте рукостискання на те, що це насправді робиться.

У TCP дві сторони відстежують, що вони надіслали, використовуючи номер послідовності. Ефективно, це в кінцевому підсумку - кількість поточних байтів, що надсилаються. Приймаюча сторона може використовувати порядковий номер оратора, який підтверджує те, що він отримав.

Але порядковий номер не починається з 0. Він починається з ISN (Initial Sequence Number), що є випадково вибраним значенням. А оскільки TCP - це двосторонній зв'язок, обидві сторони можуть "говорити", і тому обидві повинні випадковим чином генерувати ISN як свій стартовий номер послідовності. Що в свою чергу означає, що обидві сторони повинні повідомити іншу сторону про свій початковий ISN.

Отже, ви закінчите цю послідовність подій для початку розмови TCP між Алісою та Боб:

Alice ---> Bob    SYNchronize with my Initial Sequence Number of X
Alice <--- Bob    I received your syn, I ACKnowledge that I am ready for [X+1]
Alice <--- Bob    SYNchronize with my Initial Sequence Number of Y
Alice ---> Bob    I received your syn, I ACKnowledge that I am ready for [Y+1]

Зауважте, відбуваються чотири події:

  1. Аліса вибирає ISN і SYNchronize це разом з Бобом.
  2. Боб знайомий із ISN.
  3. Боб вибирає ISN і SYNchronizise його з Алісою.
  4. Аліса АСК знає ISN.

Однак насправді дві середні події (№2 та №3) відбуваються в одному пакеті. Що робить пакет a SYNабо ACKпросто двійковим прапором, включеним або вимкненим всередині кожного заголовка TCP , тому нічого не заважає обом цим прапорам ввімкнутись в одному пакеті. Отже, тристороннє рукостискання закінчується таким:

Bob <--- Alice         SYN
Bob ---> Alice     SYN ACK 
Bob <--- Alice     ACK     

Зауважте два екземпляри "SYN" та "ACK", по одному в кожному, в обох напрямках.


Отже, щоб повернутися до свого питання, чому б не просто скористатися двостороннім рукостисканням? Коротка відповідь полягає в тому, що двосторонній рукостискання дозволить лише одній стороні встановити ISN, а іншій стороні визнати це. Що означає, що лише одна сторона може надсилати дані.

Але TCP - це протокол двостороннього зв'язку, що означає, що будь-який кінець повинен мати можливість надійно надсилати дані. Обидві сторони повинні створити ІСН, і обидві сторони повинні визнати ІСН іншої.

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


6
Навіщо нам взагалі потрібні ISN? Людям це не потрібно, навіщо комп'ютери? Чи є докази цього, чи ми їх просто маємо, бо вони зручні?
Мехрдад

19
@Mehrdad: Для правильної роботи (або взагалі взагалі) вам потрібні порядкові номери. ISN не може бути просто нульовим через атаки передбачення послідовності .
Кевін

4
@Mehrdad Чат в кімнаті не обов'язково повинен бути «в реальному часі», ми можемо залишати повідомлення один одному. Причина, по якій я думав направити його кудись, - це те, що ви зараз ставите інше питання. ОП запитала "чому це 3-х тисне рукостискання замість 2", але тепер ви ставите питанням "навіщо нам взагалі потрібні номери послідовностей", що відрізняється. Замість того, щоб зірвати цю тему, я подумав, що ми повинні обговорити інше питання у чаті. Крім того , ви можете опублікувати нове запитання, я впевнений, що це добрий відповідь.
Едді

4
Чудова, лаконічна відповідь. Читання "ACK SYN" вважає принципово неправильним, але ви навіть пояснили це так +1.
Ліліенталь

3
Як повідомляє RFC 793, Протокол управління передачею : " Принципова причина тристороннього рукостискання - запобігання виникнення плутанини у старих дублікатів ініціацій з'єднання ".
Рон Моупін

23

Трьохетапного необхідно тому , що обидві сторони повинні син chronize їх порядкові номери сегментів , які використовуються в процесі їх передачі. Для цього кожен з них надсилає (у свою чергу) відрізок SYN з порядковим номером, встановленим на випадкове значення n , яке потім ack відмічається іншою стороною через сегмент ACK з порядковим номером, встановленим n + 1 .


Для чого потрібне підтвердження?
Paŭlo Ebermann

4
@ PaŭloEbermann: Тому що в іншому випадку Сервер не має уявлення, чи клієнт коли-небудь отримав SYN, і важливо, щоб клієнт отримував це.
Mooing Duck

2
@ PaŭloEbermann І щоб довести це, кроком АСК є визнання за допомогою [X + 1]. - цитується з Eddieкоментаря російської до його відповіді
smwikipedia

14

Для того, щоб з'єднання працювало, кожній стороні потрібно перевірити, чи може він пересилати пакети на іншу сторону. Єдиний спосіб бути впевненим, що ви отримали пакет на іншій стороні - це отримати від них пакет, який, за визначенням, не був би надісланий, якби пакет, який ви надіслали, отримав через . TCP по суті використовує для цього два типи повідомлень: SYN (для запиту доказу, що цей пакет пройшов) та ACK (який надсилається лише після того, як SYN проходить, щоб довести, що SYN пройшов). Насправді існує третій вид повідомлення, але ми до цього підемо миттєво.

Перед початком з'єднання жодна із сторін насправді нічого не знає про іншу. Клієнт відправляє на сервер пакет SYN, щоб вимагати підтвердження того, що його повідомлення можуть пройти . Це нікому не говорить нічого, але це перший крок рукостискання.

Якщо SYN проходить через сервер, сервер знає, що клієнт може надсилати йому пакети, тому що, ну, це просто сталося. Але це не доводить, що сервер може надсилати пакети назад: клієнти можуть надсилати SYN з безлічі причин . Таким чином, серверу потрібно відправити клієнту два повідомлення назад: ACK (щоб довести, що SYN пройшов) та SYN (вимагати власний ACK). TCP поєднує ці два повідомлення в одне-SYN-ACK повідомлення, якщо ви бажаєте - зменшити мережевий трафік. Це другий крок рукостискання.

Оскільки SYN-ACK є ACK, клієнт тепер точно знає, що може надсилати пакети на сервер. А оскільки SYN-ACK є SYN, він також знає, що сервер хоче підтвердити, що це повідомлення пройшло. Таким чином, він посилає назад ACK: на цей раз просто звичайний ACK, тому що він більше не потребує доказів того, що його пакети можуть пройти. Це останній крок рукостискання: клієнт тепер знає, що пакети можуть йти обома шляхами, і що сервер збирається це зрозуміти (адже він знає, що ACK пройде).

Як тільки цей ACK пройшов, тепер сервер знає, що він може надсилати пакети клієнту . Він також знає, що клієнт це знає, тому може почати надсилати дані відразу. Рукостискання завершено. У нас хороший канал.

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


Це неправда: "ACK (який надсилається лише у відповідь на SYN, і таким чином доводить, що SYN пройшов)." Лише перший пакет, надісланий з кожного кінця, встановлений прапор SYN, і всі пакети, окрім самого першого пакету тривимірного рукостискання, встановлені прапор ACK. Перший пакет не може ACK, оскільки друга сторона ще не SYNed, але кожен пакет після першого повинен перевірити все, що вже було отримано з іншого кінця, будь-які дані передані назад чи ні.
Monty Harder

Дякую. Переформатування: ACK надсилаються, як тільки SYN проходить, а не надсилається лише у відповідь на SYN.
Найгірший

Це найкраща відповідь, яка може логічно пояснити, чому нам навіть потрібне третє повідомлення. Спасибі, найгірший
Parth Patel

7

Насправді тристоронній рукостискання - не єдиний засіб встановлення TCP-з'єднання. Дозволений також одночасний обмін SYN: http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-4.htm

Це можна було б розглянути як своєрідне подвійне двостороннє рукостискання.


1
Добре, однак, це дуже рідко, оскільки обом пристроям доведеться використовувати один і той же вихідний / вихідний порт, і обом пристроям потрібно буде надіслати SYN, перш ніж інший отримає SYN. Навіть коли це відбувається, це передбачає відправлення чотирьох пакетів, що більше, ніж три пакети, необхідні для традиційного тристороннього рукостискання; в кінцевому рахунку лише можливість трохи швидше налаштуватись за загальним часом за рахунок меншої загальної ефективності (потрібно на 33% більше пакетів для передачі).
YLearn

4

TCP-з'єднання двостороннє. Це означає, що це насправді пара односторонніх зв’язків. Ініціатор посилає SYN, відповідач посилає ACK: починається одне симплексне з'єднання. "Потім" відповідь посилає SYN, ініціатор посилає ACK: починається ще одне симплексне з'єднання. Два симплексні з'єднання утворюють один двосторонній сеанс TCP, погодьтеся? Отже, логічно, є чотири кроки; але оскільки прапори SYN та ACK - це різні "поля" заголовка TCP, їх можна встановити одночасно - другий і третій кроки (з чотирьох) поєднуються, тому технічно існує три обміни пакетів. Кожне симплексне (напів-) з'єднання використовує двосторонній обмін, як ви запропонували.


2

Якщо Сервер і Клієнт хочуть створити з'єднання, їм потрібно підтвердити чотири речі:

  1. Сервер повинен підтвердити, що він може отримати пакет від Клієнта
  2. Клієнт повинен підтвердити, що він може отримати пакет від Сервера

  3. Клієнт повинен підтвердити річ: Сервер може отримувати пакет від Клієнта

  4. Сервер повинен щось підтвердити: Клієнт може отримати пакет від Сервера

Після цього Client ------SYN-----> Serverправило 1 підтверджується.

Після цього Client <---ACK/SYN---- Serverправила 2 і 3 підтверджуються.

Отже, для підтвердження правила 4 потрібен третій пакет.


1

Це зовсім не обов’язково. Очевидно, що для короткого повідомлення сервер повинен вимагати лише один пакет, який включає в себе повідомлення "старт +", і один пакет назад, що підтверджує його.

Попередні відповіді просто описують систему, не обговорюючи необхідності випадкових порядкових чисел тощо. Первісне питання стосувалося самої конструкції TCP - очевидно, якщо ви використовуєте протокол TCP, тоді вам потрібно три повідомлення, тому що це протокол. Але чому в першу чергу був розроблений TCP?

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

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

(Зауважте, що мова йде про двонаправлене ініціювання з'єднання, яке ніколи не робиться сьогодні. Це зовсім відрізняється від надсилання двонаправлених повідомлень вниз після встановлення з'єднання.)

Щоб подолати неефективність TCP, ми використовуємо такі протоколи, як HTTP 1.1, які можуть повторно використовувати одне і те ж з'єднання для декількох запитів, і, таким чином, уникати рукостискання TCP, що в першу чергу не було необхідним.

Але Http 1.1 порівняно новий. І SSL / TLS потребував способу повторного використання сеансу з самого початку через вартість алгоритмів PKI. Таким чином, цей протокол включає власний механізм повторного використання сеансу, який працює над Http 1.1, який працює поверх TCP.

Такий шлях із програмним забезпеченням. Випади каламуті, які в поєднанні дають прийнятний результат.


Все вище рівня 4 OSI (наприклад, HTTP, FTP тощо) тут явно поза темою. У шарах від 1 до 4 немає такого поняття, як клієнт / сервер. TCP - це зв'язок між однолітками. Так, протоколи верхнього шару створюють відносини клієнт / сервер, але це тут поза темою.
Рон Моупін

1
До речі, HTTP використовує TCP, тому рукостискання TCP все ще необхідно. Прочитайте RFC 793 ПРОТОКОЛ КОНТРОЛЬНОГО ПРИЙМАННЯ, щоб відмовитись від того, чому. Такі протоколи, як HTTP, вимагають від програми виконувати мультиплексування, як правило, TCP для цього додатка.
Рон Моупін

@RonMaupin Первісне питання було чому? І відповідь - підтримка випадку використання, який ніколи не використовується верхніми рівнями рівня на практиці. Отже, здається досить актуальним.
Tuntable

@RonMaupin Так, HTTP використовує TCP. Що я уточнив, дякую. Але це не робить рукостискання TCP необхідним у глибокому розумінні.
Tuntable

1
Програми та протоколи на рівні додатків тут явно поза темою. @Eddie відповів на питання, і якщо ви прочитаєте та зрозумієте TCP RFC, ви отримаєте, чому рукостискання необхідне. Я не думаю, що це додає вам нічого, щоб стверджувати, без будь-якої підтримки, що рукостискання не потрібно, коли це очевидно.
Рон Моупін

1

Прочитавши відповідь Едді (прийнято як правильну), все ще виникає питання, чому 1-й хост не може призначити обидва ISN випадковими числами, а другий просто прийняти його. Справжня причина використання тристороннього рукостискання - уникати напівз’єднань . Половина сценарію підключення в двосторонньому рукостисканні:
1) Клієнт --- SYN -> Сервер
2) Клієнт передумав і більше не хоче підключатися
3) Клієнт <-X-ACK-- Сервер // ACK втрачено
Сервер не бачить обуреного SYN, тому він вважає, що клієнт отримав свій ACK і з'єднання встановлено. В результаті сервер має з'єднання, яке ніколи не буде закритим


Насправді, якщо хост (клієнти та сервери - це концепція програми, про яку TCP нічого не знає) отримує ACK або будь-який трафік на неіснуючому з'єднанні (крок 3 у вашому сценарії), він відправить RST, а не ігнорує отриманий сегмент .
Рон Моупін

@RonMaupin Тоді припустимо ситуацію, коли пакет ACK був втрачений.
Санжар Єлеуов

Якщо ACK втрачено, ініційоване з'єднання на кроці 1 закінчиться. RFC 793 має повне пояснення всіх типів сценаріїв, включаючи діаграми.
Рон Моупін

@RonMaupin Я маю на увазі, якщо сценарій з моєї посади залишиться тим самим, єдине, що змінилося, це втрачено ACK.
Санжар Єлеуов

Це все в RFC. Поки з'єднання не відкрите, будь-який отриманий трафік призведе до RST. Тристоронній рукостискання узгоджує параметри з'єднання, тому "сервер" нічого не може повернути "клієнту", але це SYN / ACK, поки не отримає ACK від "клієнта". Якщо "сервер" SYN / ACK назад до "клієнта" втрачено, "сервер" спробує ще раз. RFC пояснює все це.
Рон Мопін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.