Що таке tcp сервер? Що таке протокол TCP-IP? Встановлення з'єднання TCP

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

Що це за технологія? Назва TCP-IP походить від двох мережевих протоколів: TCP та IP. Звичайно, цими двома протоколами побудова мереж не обмежується, але вони є базовими у тому, що стосується саме організації передачі даних. Фактично TCP-IP є набір протоколів, що дозволяють індивідуальним мережам об'єднуватися для освіти

Протокол TCP-IP, опис якого неможливо позначити лише визначеннями IP і TCP, включає також протоколи UDP, SMTP, ICMP, FTP, telnet, і не тільки. Ці та інші протоколи TCP-IP забезпечують найбільше повноцінну роботуІнтернет.

Нижче наведемо розгорнуту характеристику кожному протоколу, що входить у загальне поняття TCP-IP.

. Інтернет-протокол(IP) відповідає за безпосередню передачу інформації у мережі. Інформація ділиться на частини (тобто пакети) і передається одержувачу від відправника. Для точної адресації потрібно вказати точну адресу або координати одержувача. Такі адреси складаються з чотирьох байт, які відокремлені один від одного крапками. Адреса кожного комп'ютера є унікальною.

Однак використання одного лише IP-протоколу може бути недостатньо для коректної передачі даних, так як обсяг більшої частини інформації, що пересилається, більше 1500 символів, що вже не вписується в один пакет, а деякі пакети можуть бути втрачені в процесі передачі або надіслані не в тому порядку, що потрібно.

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

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

1. FTP(File Transfer Protocol) організує перенесення файлів і використовується для передачі інформації між двома вузлами Internet з використанням TCP-з'єднань у вигляді бінарного або простого текстового файлу, як іменовані області в пам'яті комп'ютера. При цьому немає ніякого значення, де дані вузли розташовані і як з'єднуються між собою.

2. Протокол користувацьких дейтаграм, або User Datagram Protocol, не залежить від підключень, він передає дані пакетами, які називають UDP-дейтаграмами. Однак цей протокол не такий надійний, як TCP, тому що отруйник не отримує даних про те, чи був прийнятий пакет насправді.

3. ICMP(Internet Control Message Protocol) існує для того, щоб надсилати повідомлення про помилки, що виникають у процесі обміну даними в мережі Internet. Однак при цьому ICMP-протокол тільки повідомляє про помилки, але не усуває причини, які призвели до виникнення цих помилок.

4. Telnet- який використовується для реалізації текстового інтерфейсу мережі за допомогою транспорту TCP.

5. SMTP(Simple Mail Transfer Protocol) – це спеціальний електронними повідомленнями, визначальний формат повідомлень, що пересилаються з одного комп'ютера, званого SMTP-клієнтом, на інший комп'ютер, на якому запущено SMTP-сервер. При цьому дана пересилка може бути відкладена на деякий час, доки не активується робота як клієнта, так і сервера.

Схема передачі за протоколом TCP-IP

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

3. Потім за допомогою протоколу TCP відбувається перевірка того, чи всі отримані пакети. Якщо під час прийому обчислена заново не збігається із зазначеною на конверті, це свідчить про те, що частина інформації була втрачена або спотворена під час передачі, протокол TCP-IP знову запитує пересилання цього пакета. Також потрібне підтвердження надходження даних від одержувача.

4. Після підтвердження отримання всіх пакетів протокол TCP упорядковує їх відповідним чином і збирає заново єдине ціле.

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

Тим самим протокол TCP-IP знімає необхідність використання повторних передач та очікувань для прикладних процесів (таких як Telnet і FTP).

На транспортному рівні стеку TCP/IPвикористовуються два основні протоколи: TCPі UDP. Загальне уявленняпро функції транспортного рівня можна одержати відповідною статтею. У цьому тексті йдеться про протокол TCP (Transmission Control Protocol), який використовується для забезпечення надійної доставки даних на транспортному рівні.

Існують загальні завдання транспортного рівня, з якими справляється як TCP, і UDP . Основних завдань власне дві: сегментація даних, що приходять з рівня додатків та адресація додатків(передаючого та приймаючого) за допомогою портів. Докладніше про це можна прочитати у статті, присвяченій транспортному рівню.

Крім цього, TCP забезпечує:

  • Надійну доставку сегментів.
  • Упорядкування сегментів при отриманні.
  • Роботу із сесіями.
  • Контроль за швидкістю передачі.

Розглянемо ці можливості детальніше.

Надійна доставка сегментів

Під надійною доставкою мається на увазі автоматичне повторне пересилання сегментів, що не дійшли. Кожен сегмент маркується за допомогою спеціального поля – порядкового номера (sequence number). Після відправки деякої кількості сегментів, TCP на відправляючому вузлі очікує підтвердження від одержувача, в якому вказується порядковий номернаступного сегмента, який адресат хоче отримати. Якщо таке підтвердження не отримано, надсилання автоматично повторюється. Після деякої кількості невдалих спроб TCP вважає, що адресат не доступний, і сесія розривається.

Таким чином, надійна доставкане означає, що ваші дані дійдуть у випадку, якщо хтось висмикнув кабель з комутатора. Вона означає, що розробник ПЗ, що використовує TCP на транспортному рівні знає, що якщо сесія не розірвалася, то все, що він доручив відправити, буде доставлено одержувачу без втрат. Існує безліч даних, критичних до втрати будь-якої порції інформації. Наприклад, якщо ви завантажуєте програму з інтернету, то втрата одного байта означатиме, що ви не зможете скористатися тим, що завантажили. З цієї причини багато протоколів рівня додатків використовують для транспортування TCP.

Упорядкування сегментів при отриманні

Як легко здогадатися, кожен сегмент на нижній рівнях TCP/IP обробляється індивідуально. Тобто, як мінімум, його буде запаковано в індивідуальний пакет. Пакети йдуть по мережі та проміжні маршрутизатори в загальному випадку вже нічого не знають про те, що запаковано у ці пакети. Часто пакети з метою балансування навантаження можуть йти по мережі різними шляхами через різні проміжні пристрої з різною швидкістю. Таким чином одержувач, декапсулюючи їх, може отримати сегменти не в тому порядку, в якому вони відправлялися.

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

Робота із сесіями

Перед початком передачі корисних даних TCP дозволяє переконатися в тому, що одержувач існує, слухає потрібний відправнику порт і готовий приймати дані для цього встановлюється сесія за допомогою механізму тристороннього рукостискання (three-way handshake), про який можна прочитати у відповідній статті. Далі, в рамках сесії передаються корисні дані користувача. Після завершення передачі сесія закривається, тим самим одержувач сповіщається про те, що даних більше не буде, а відправник сповіщається про те, що одержувач сповіщений.

Контроль за швидкістю передачі

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

Завдяки механізму ковзного вікна (sliding window) TCP може працювати з мережами різної надійності. Механізм плаваючого вікна дозволяє змінювати кількість байтів, що пересилаються, на які треба отримувати підтвердження від адресата. Чим більший розмір вікна, тим більше більший обсягінформації буде передано до отримання підтвердження. Для надійних мережпідтвердження можна надсилати рідко, щоб не додавати трафіку, тому розмір вікна у таких мережах автоматично збільшується. Якщо ж TCP бачить, що дані втрачаються, розмір вікна автоматично зменшується. Це пов'язано з тим, що якщо ми передали, наприклад, 3 кілобайти інформації та не отримали підтвердження, то ми не знаємо, яка конкретно частина з них не дійшла і змушені пересилати всі три кілобайти заново. Таким чином, для ненадійних мереж розмір вікна повинен бути мінімальним.

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

Структура TCP

Заголовок TCP сегмента має таку структуру:

  • Source port і Destination port - це відповідно номери портів одержувача і відправника, що ідентифікують додатків на вузлах, що відправляє і приймає.
  • Sequence number та Acknowledgment number – це порядковий номер сегмента та номер підтвердження, які використовуються для надійної доставки. Наприклад, якщо відправник шле сегмент із SN 100, то одержувач може відповісти на нього ACK 101 SN200, що означає: «Я отримав твій сегмент із номером 100 і чекаю від тебе 101-го, до речі, у мене своя нумерація. Мої номери починаються з 200» Відправник, у свою чергу, може відповісти SN101 ACK201, що означає «Я отримав від тебе сегмент з номером 200, можу прийняти наступний 201-й, а ось тобі мій 101-й сегмент, якого ти чекаєш». Ну і таке інше.
  • Header length - це чотирибітне поле, що містить у собі довжину заголовка TCP сегмента.
  • Reserved - 6 зарезервованих про всяк випадок біт.
  • Control - поле з прапорами, що використовуються у процесі обміну інформацією та описують додаткове призначення сегмента. Наприклад, прапор FIN використовується для завершення з'єднань, SYN та ACK - для встановлення.
  • Window містить розмір вікна, про що було сказано вище.
  • Checksumm - контрольна сума заголовка та даних.
  • Urgent – ​​ознака важливості (терміновості) даного сегмента.
  • Options - додаткове необов'язкове поле, яке можна використовувати, наприклад, для тестування протоколу.
  • У розділі даних містяться дані, отримані від протоколу рівня додатків, або їх шматок, якщо дані довелося розбивати.

В основі роботи глобальної мережіІнтернет лежить набір (стек) протоколів TCP/IP. Але ці терміни лише з погляду здаються складними. Насправді стек протоколів TCP/IP- це простий набір правил обміну інформацією, і ці правила насправді вам добре відомі, хоч ви, ймовірно, про це і не здогадуєтеся. Так, все саме так, по суті, в принципах, що лежать в основі протоколів TCP/IP, немає нічого нового: все нове – це добре забуте старе.

Людина може навчатися двома шляхами:

  1. Через тупе формальне зазубрювання шаблонних способів вирішення типових завдань(Чому зараз переважно і навчають у школі). Таке навчання є малоефективним. Напевно, вам доводилося спостерігати паніку і повну безпорадність бухгалтера при зміні версії офісного софту - при найменшій зміні послідовності кліків мишки, необхідних для виконання звичних дій. Чи доводилося бачити людину, яка впадає у ступор при зміні інтерфейсу робочого столу?
  2. Через розуміння суті проблем, явищ, закономірностей. Через розуміння принципівпобудови тієї чи іншої системи. У цьому випадку володіння енциклопедичними знаннями не відіграє великої ролі - інформацію, яку бракує, легко знайти. Головне – знати, що шукати. А для цього потрібне не формальне знання предмета, а розуміння суті.

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

Тож почнемо.

Принципи роботи інтернет-протоколів TCP/IP за своєю суттю дуже прості та дуже нагадують роботу нашої радянської пошти.

Згадайте, як працює наша пошта. Спочатку ви на листку пишете листа, потім кладете його в конверт, заклеюєте, на зворотній стороніконверта пишете адреси відправника та одержувача, а потім відносите до найближчого відділення пошти. Далі лист проходить через ланцюжок поштових відділень до найближчого поштового відділення одержувача, звідки воно тіткою-листоном доставляється до вказаною адресоюодержувача та опускається до його поштової скриньки (з номером його квартири) або вручається особисто. Все, лист дійшов до отримувача. Коли одержувач листа захоче вам відповісти, то він у своєму листі у відповідь поміняє місцями адреси одержувача і відправника, і лист відправитися до вас по тому ж ланцюжку, але в зворотному напрямку.

На конверті листа буде написано приблизно таке:

Адреса відправника: Від кого: Іванов Іван Іванович Звідки: Івантіївка, вул. Велика, буд. 8, кв. 25 Адреса одержувача: Кому: Петров Петро Петрович Куди: Москва, Усачевський провулок, буд. 105, кв. 110

Тепер ми готові розглянути взаємодію комп'ютерів та додатків у мережі Інтернет (та й у локальної мережітеж). Зверніть увагу, що аналогія із звичайною поштою буде майже повною.

Кожен комп'ютер (він же: вузол, хост) у рамках мережі Інтернет теж має унікальну адресу, яка називається IP-адреса (Internet Protocol Address), наприклад: 195.34.32.116. IP адреса складається з чотирьох десяткових чисел(Від 0 до 255), розділених точкою. Але знати лише IP адресу комп'ютера недостатньо, т.к. зрештою обмінюються інформацією не комп'ютери власними силами, а докладання, які працюють у них. А на комп'ютері може одночасно працювати відразу кілька програм (наприклад, поштовий сервер, веб-сервер тощо). Для доставки звичайного паперового листа недостатньо знати лише адресу будинку - ще необхідно знати номер квартири. Також кожен програмний додаток має подібний номер, іменований номером порту. Більшість серверних додатківмають стандартні номери, наприклад: поштовий сервісприв'язаний до порту з номером 25 (ще говорять: «слухає» порт, приймає повідомлення), веб-сервіс прив'язаний до порту 80, FTP - до порту 21 тощо.

Таким чином маємо наступну практично повну аналогію з нашою звичайною поштовою адресою:

"адреса будинку" = "IP комп'ютера" "номер квартири" = "номер порту"

У комп'ютерних мережах, що працюють за протоколами TCP/IP, аналогом паперового листа в конверті є пакет, який містить власне передані дані та адресну інформацію - адресу відправника та адресу одержувача, наприклад:

Адреса відправника (Source address): IP: 82.146.49.55 Port: 2049 Адреса одержувача (Destination address): IP: 195.34.32.116 Port: 53 Дані пакету: ...

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

Зверніть увагу, комбінація: "IP адреса та номер порту" -називається "сокет".

У прикладі ми з сокету 82.146.49.55:2049 посилаємо пакет на сокет 195.34.32.116:53, тобто. пакет піде на комп'ютер, що має IP адресу 195.34.32.116, порт 53. А порту 53 відповідає сервер розпізнавання імен (DNS-сервер), який прийме цей пакет. Знаючи адресу відправника, цей сервер зможе після обробки нашого запиту сформувати пакет у відповідь, який піде у зворотному напрямку на сокет відправника 82.146.49.55:2049, який для DNS сервера буде сокетом одержувача.

Як правило, взаємодія здійснюється за схемою «клієнт-сервер»: "клієнт" запитує будь-яку інформацію (наприклад сторінку сайту), сервер приймає запит, обробляє його і посилає результат. Номери портів серверних програм загальновідомі, наприклад: поштовий SMTPсервер «слухає» 25-й порт, POP3 сервер, що забезпечує читання пошти з ваших поштових скриньок «слухає» 110-порт, веб-сервер – 80-й порт тощо.

Більшість програм на домашньому комп'ютеріє клієнтами – наприклад поштовий клієнт Outlook, веб-браузери IE, FireFox та ін.

Номери портів на клієнті не фіксовані як сервер, а призначаються операційною системою динамічно. Фіксовані серверні порти зазвичай мають номери до 1024 (але є винятки), а клієнтські починаються після 1024.

Повторення – мати навчання: IP – це адреса комп'ютера (вузла, хоста) у мережі, а порт – номер конкретного додаткупрацює на цьому комп'ютері.

Однак людині запам'ятовувати цифрові IP адреси важко - зручніше працювати з літерними іменами. Адже набагато легше запам'ятати слово, аніж набір цифр. Так і зроблено - будь-яку цифрову IP адресу можна пов'язати з буквено-цифровим ім'ям. В результаті наприклад замість 82.146.49.55 можна використовувати ім'я А перетворенням доменного імені на цифрову IP адресу займається сервіс доменних імен - DNS (Domain Name System).

Розглянемо докладніше, як це працює. Ваш провайдер явно (на папірці, для ручного налаштуванняз'єднання) або неявно (через автоматичне налаштування з'єднання) надає вам IP-адресу сервера імен (DNS). На комп'ютері з цією IP адресою працює програма (сервер імен), яка знає всі доменні імена в Інтернеті та відповідні цифрові IP адреси. DNS-сервер «слухає» 53-й порт, приймає на нього запити та видає відповіді, наприклад:

Запит від нашого комп'ютера: "Яка IP-адреса відповідає імені www.сайт?" Відповідь сервера: "82.146.49.55."

Тепер розглянемо, що відбувається, коли у своєму браузері ви набираєте доменне ім'я (URL) цього сайту () і натиснувши У відповідь від веб-сервера отримуєте сторінку цього сайту.

Наприклад:

IP адреса нашого комп'ютера: 91.76.65.216 Браузер: Internet Explorer (IE), DNS сервер (стрим): 195.34.32.116 (у вас може бути інший), Сторінка, яку ми хочемо відкрити: www.сайт.

Набираємо в адресному рядкубраузера доменне ім'я та тиснемо . Далі операційна системаробить приблизно такі дії:

Надсилається запит (точніше пакет із запитом) DNS серверуна сокет 195.34.32.116:53. Як було розглянуто вище, порт 53 відповідає DNS-серверу - додатку, що займається розпізнаванням імен. А DNS-сервер, обробивши наш запит, повертає IP-адресу, яка відповідає введеному імені.

Діалог приблизно наступний:

Яка IP адреса відповідає імені www.сайт? - 82.146.49.55 .

Далі наш комп'ютер встановлює з'єднання з портом 80 комп'ютера 82.146.49.55 та посилає запит (пакет із запитом) на отримання сторінки . 80-й порт відповідає веб-серверу. У адресному рядку браузера 80-й порт зазвичай пишеться, т.к. використовується за умовчанням, але його можна і явно вказати після двокрапки - .

Прийнявши від нас запит, веб-сервер обробляє його і в декількох пакетах посилає нам сторінку в мові HTML - мові розмітки тексту, який розуміє браузер.

Наш браузер, отримавши сторінку, відображає її. В результаті, ми бачимо на екрані головну сторінку цього сайту.

Навіщо ці принципи треба розуміти?

Наприклад, ви помітили дивна поведінкасвого комп'ютера – незрозуміла мережна активність, гальма та ін. Що робити? Відкриваємо консоль (натискаємо кнопку «Пуск» – «Виконати» – набираємо cmd – «Ок»). У консолі набираємо команду netstat -anі тиснемо . Ця утиліта відобразить список встановлених з'єднань між сокетами комп'ютера та сокетами віддалених вузлів. Якщо ми бачимо в колонці «Зовнішня адреса» якісь чужі IP-адреси, а через двокрапку 25-й порт, що це може означати? (Пам'ятайте, що 25-й порт відповідає поштовому серверу?) Це означає, що ваш комп'ютер встановив з'єднання з якимось поштовим сервером(серверами) і надсилає через нього якісь листи. І якщо ваш поштовий клієнт(Outlook наприклад) у цей час не запущено, та якщо ще таких з'єднань на 25-й порт багато, то, ймовірно, у вашому комп'ютері завівся вірус, який розсилає від вашого імені спам або пересилає номери ваших кредитних карток разом із паролями зловмисникам.

Також розуміння принципів роботи Інтернету необхідне правильного налаштуванняфаєрволла (простіше кажучи брандмауера:)). Ця програма (яка часто поставляється разом з антивірусом), призначена для фільтрації пакетів - "своїх" та "ворожих". Своїх пропускати, чужих не пускати. Наприклад, якщо ваш фаєрвол повідомляє вам, що хтось хоче встановити з'єднання з будь-яким портом вашого комп'ютера. Дозволити чи заборонити?

Ну і найголовніше – ці знання вкрай корисні при спілкуванні з техпідтримкою.

Насамкінець наведу список портів, з якими вам, ймовірно, доведеться зіткнутися:

135-139 - ці порти використовуються Windows для доступу до загальним ресурсамкомп'ютера – папкам, принтерам. Не відкривайте ці порти назовні, тобто. в районну локальну мережу та Інтернет. Їх слід закрити фаєрволом. Також якщо в локальній мережі ви не бачите нічого в мережевому оточенніабо вас не бачать, то ймовірно це пов'язано з тим, що фаєрвол заблокував ці порти. Таким чином, для локальної мережі ці порти повинні бути відкриті, а для Інтернету закриті. 21 - порт FTPсервера. 25 - порт поштового SMTPсервера. Через нього ваш поштовий клієнт надсилає листи. IP адреса SMTPсервера та його порт (25-й) слід вказати у налаштуваннях вашого поштового клієнта. 110 - порт POP3сервера. Через нього ваш поштовий клієнт забирає листи з вашого поштової скриньки. IP адресу POP3 сервера та його порт (110-й) також слід вказати в налаштуваннях вашого поштового клієнта. 80 - порт WEB-Сервера. 3128, 8080 - проксі-сервери (налаштовуються у параметрах браузера).

Декілька спеціальних IP адрес:

127.0.0.1 – це localhost, адреса локальної системи, тобто. локальну адресу вашого комп'ютера. 0.0.0.0 – так позначаються всі IP-адреси. 192.168.xxx.xxx - адреси, які можна довільно використовувати в локальних мережах, у глобальній мережі Інтернет вони не використовуються. Вони унікальні лише у межах локальної мережі. Адреси з цього діапазону можна використовувати на свій розсуд, наприклад, для побудови домашньої або офісної мережі.

Що таке маска підмережі та шлюз за замовчуванням (роутер, маршрутизатор)?

(Ці параметри задаються у настройках мережевих підключень).

Все просто. Комп'ютери об'єднуються у локальні мережі. У локальній мережі комп'ютери безпосередньо «бачать» лише одне одного. Локальні мережі з'єднуються між собою через шлюзи (роутери, маршрутизатори). Маска підмережі призначена для визначення - чи належить комп'ютер-одержувач до цієї локальної мережі чи ні. Якщо комп'ютер-одержувач належить цієї мережі, як і комп'ютер-відправник, то пакет передається йому безпосередньо, інакше пакет відправляється на шлюз за замовчуванням, який далі, за відомими йому маршрутами, передає пакет іншу мережу, тобто. до іншого поштового відділення (за аналогією з радянською поштою).

Насамкінець розглянемо що ж означають незрозумілі терміни:

TCP/IP- це назва набору мережевих протоколів. Насправді пакет, що передається, проходить кілька рівнів. (Як на пошті: спочатку ви пишете лист, потім поміщаєте в конверт з адресою, потім поштою на ньому ставиться штамп і т.д.).

IPпротокол – це протокол так званого мережевого рівня. Завдання цього рівня - доставка IP-пакетів від комп'ютера відправника до комп'ютера одержувачу. Крім власне даних, пакети цього рівня мають ip-адресу відправника та ip-адресу одержувача. Номери портів на мережевому рівніне використовуються. Якому порту, тобто. додатку адресовано цей пакет, був цей пакет доставлений чи був втрачений, цьому рівні невідомо - це його завдання, це завдання транспортного рівня.

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

TCP- це протокол із встановленням з'єднання та з гарантованою доставкою пакетів. Спочатку проводиться обмін спеціальними пакетами для встановлення з'єднання, відбувається щось на зразок рукостискання (-Привіт. -Привіт. -Побалакаємо? -Давай.). Далі цим з'єднанням туди і назад посилаються пакети (йде розмова), причому з перевіркою, чи дійшов пакет до одержувача. Якщо пакет не дійшов, він посилається повторно («повтори, не почув»).

UDP- це протокол без встановлення з'єднання та з негарантованою доставкою пакетів. (Типу: крикнув щось, а почують тебе чи ні – неважливо).

Над транспортним рівнем знаходиться прикладний рівень. На цьому рівні працюють такі протоколи, як http, ftpта ін. Наприклад HTTP та FTP - використовують надійний протокол TCP, а DNS-сервер працює через ненадійний протокол UDP.

Як переглянути поточні з'єднання?

Поточні з'єднання можна переглянути за допомогою команди

Netstat-an

(Параметр n вказує виводити IP адреси замість доменних імен).

Запускається ця команда в такий спосіб:

«Пуск» – «Виконати» – набираємо cmd – «Ок». У консолі (чорне вікно), що з'явилася, набираємо команду netstat -an і тиснемо . Результатом буде список встановлених з'єднань між сокетами нашого комп'ютера та віддалених вузлів.

Наприклад, отримуємо:

Активні підключення

Ім'я Локальна адреса Зовнішня адреса Стан
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING
TCP 91.76.65.216:139 0.0.0.0:0 LISTENING
TCP 91.76.65.216:1719 212.58.226.20:80 ESTABLISHED
TCP 91.76.65.216:1720 212.58.226.20:80 ESTABLISHED
TCP 91.76.65.216:1723 212.58.227.138:80 CLOSE_WAIT
TCP 91.76.65.216:1724 212.58.226.8:80 ESTABLISHED
...

У цьому прикладі 0.0.0.0:135 означає, що наш комп'ютер на всіх своїх IP адресах слухає (LISTENING) 135-й порт і готовий приймати на нього з'єднання від будь-кого (0.0.0.0:0) за протоколом TCP.

91.76.65.216:139 – наш комп'ютер слухає 139-й порт на своїй IP-адресі 91.76.65.216.

Третій рядок означає, що зараз встановлено (ESTABLISHED) з'єднання між нашою машиною (91.76.65.216:1719) та віддаленою (212.58.226.20:80). Порт 80 означає, що наша машина звернулася із запитом до веб-сервера (у мене дійсно відкриті сторінки в браузері).

У наступних статтях ми розглянемо, як застосовувати ці знання, наприклад

Глава 18 Встановлення та розрив TCP з'єднання

Вступ

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

Оскільки для роботи TCP необхідно встановити з'єднання між двома кінцями, він відрізняється від протоколів без з'єднання, таких як UDP. У розділі 11 ми бачили, що з використанні UDP кожна сторона просто відсилає датаграми інший, не встановивши перед цим з'єднання.

Встановлення та розрив з'єднання

Для того, щоб подивитися, що відбувається при встановленні та розриві TCP з'єднання, ми виконали на системі svr4 наступну команду:

Svr4% telnet bsdi discard
Trying 192.82.148.3 ...
Connected to bsdi.
Escape character is "^]".
^] вводимо Control, праву квадратну дужку,
telnet> quitщоб Telnet клієнт розірвав з'єднання
Connection closed.

Команда telnet встановлює TCP з'єднання з хостом bsdi на порт, що відповідає discard сервісу (глава 1, розділ "Стандартні прості сервіси"). Це саме тип сервісу, який нам необхідний, щоб подивитися, що відбувається при встановленні та розриві з'єднання, але без обміну даними.

Висновок tcpdump

На малюнку 18.1 показаний висновок tcpdump для сегментів, згенерованих цією командою.

1 0.0 svr4.1037 > bsdi.discard: S 1415531521:1415531521 (0)
win 4096
2 0.002402 (0.0024) bsdi.discard > svr4.1037: S 1823083521:1823083521 (0)
ack 1415531522 win 4096

3 0.007224 (0.0048) svr4.1037 > bsdi.discard: . ack 1823083522 win 4096
4 4.155441 (4.1482) svr4.1037 > bsdi.discard: F 1415531522:1415531522 (0)
ack 1823083522 win 4096
5 4.156747 (0.0013) bsdi.discard > svr4.1037: . ack 1415531523 win 4096
6 4.158144 (0.0014) bsdi.discard > svr4.1037: F 1823083522:1823083522 (0)
ack 1415531523 win 4096
7 4.180662 (0.0225) svr4.1037 > bsdi.discard: . ack 1823083523 win 4096

Рисунок 18.1 Виведення tcpdump для встановлення та розриву TCP з'єднання.

Ці сім сегментів TCP містять тільки TCP заголовки. Обмін даними не здійснювалося.

Для TCP сегментів кожен вихідний рядок починається з

source > destination: flags (джерело > призначення: прапори)

де прапори (flags) є чотири з шести прапорових бітів TCP заголовка (рисунок 17.2). На малюнку 18.2 показано п'ять різних символів, які відповідають прапорам та можуть з'явитися у виводі.

прапор

3-символьне скорочення

Опис

синхронізуючі номери послідовності
відправник закінчив передачу даних
скидання з'єднання
відправка даних приймаючого процесу настільки швидко, наскільки це можливо
жоден із чотирьох прапорів не встановлений

Рисунок 18.2 Символи прапорів, виведені командою tcpdump для прапорових бітів у заголовку TCP.

У цьому прикладі бачимо прапори S, F і точку. Ще два прапори (R та P) з'являться пізніше. Два інших біт прапорів в TCP заголовку - ACK і URG - надруковані командою tcpdump.

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

RFC 1025 [ Postel 1987] називає сегмент, в якому максимальна комбінація всіх доступних прапорових бітів зведена одночасно (SYN, URG, PSH, FIN та 1 байт даних) пакетом Камікадзе (в англійській мові існує ще кілька визначень такого пакету, а саме - "брудний" пакет", "пакет Новорічної ялинки" і т.п.).

У рядку 1 поле 1415531521:1415531521 (0) означає, що номер послідовності пакета дорівнює 1415531521, а кількість байт даних у сегменті дорівнює 0. Команда tcpdump друкує початковий номер послідовності, двокрапка, передбачуваний заключний номер послідовності. При цьому існує можливість переглянути передбачуваний остаточний номер послідовності, коли кількість байтів більше ніж 0. У полі з'являється (1), якщо сегмент містить один або кілька байт даних, або (2) якщо зведені прапор SYN, FIN або RST. У рядках 1, 2, 4 і 6 малюнку 18.1 це поле з'являється, оскільки зведені прапорові біти - обмін будь-якими даними у цьому прикладі не проводився.

У рядку 2 поле ack 1415531522 містить номер підтвердження. Воно друкується лише тоді, коли прапор ACK зведений. Поле win 4096 у кожному рядку виводу показує розмір вікна, яке було оголошено відправником. У цьому прикладі, де не здійснювався обмін даними, розмір вікна залишався незмінним і використовувалася за замовчуванням величина - 4096. (Ми розглянемо розмір вікна TCP у розділі "Розмір вікна" глави 20.)

І останнє поле у ​​виведенні малюнку 18.1, показує максимальний розмір сегмента (MSS - maximum segment size), опція, яку встановлює відправник. Відправник не хоче отримувати TCP сегменти більше, ніж це значення. Це зазвичай робиться для того, щоб уникнути фрагментації (глава 11, розділ "Фрагментація IP"). Ми розглянемо максимальний розмір сегмента у розділі цього розділу, а формат різних опцій TCP покажемо розділ цього розділу.

Тимчасові діаграми

На малюнку 18.3 показана часова діаграма, що відповідає цьому обміну пакетами. (Ми описали деякі основні характеристики часових діаграм, коли вперше звернулися до малюнка 6.11.) На цьому малюнку показано, яка сторона відправляє пакети. Також наведено висновок команди tcpdump (на друк виводилося SYN замість S). У цій часовій діаграмі видалено значення розміру вікна, оскільки це не суттєво для нашого обговорення.

Протокол встановлення з'єднання

А тепер давайте повернемося до деталей протоколу TCP, які показані на малюнку 18.3. Щоб встановити TCP з'єднання, необхідно:

  1. Сторона, що запитує (яка, як правило, називається клієнт) відправляє SYN сегмент, вказуючи номер порту сервера, до якого клієнт хоче приєднатися, і вихідний номер послідовності клієнта (в даному прикладі ISN, 1415531521). Це сегмент №1.
  2. Сервер відповідає своїм сегментом SYN, що містить вихідний номер серії послідовності (сегмент 2). Сервер також підтверджує прихід клієнта SYN з використанням ACK (ISN клієнта плюс один). На SYN використовується один номер послідовності.
  3. Клієнт повинен підтвердити надходження SYN від сервера з використанням ACK (ISN сервера плюс один, сегмент 3).

Цих трьох сегментів достатньо встановлення з'єднання. Часто це називається триразовим рукостисканням (three-way handshake).

Рисунок 18.3 Тимчасова діаграма встановлення та розриву з'єднання.

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

Коли кожна сторона надіслала свій SYN щоб встановити з'єднання, вона вибирає вихідний номер послідовності (ISN) для цього з'єднання. ISN повинен змінюватися кожного разу, тому кожне з'єднання має свій, відмінний від інших ISN. RFC 793 [ Postel 1981c] вказує, що ISN є 32-бітним лічильником, який збільшується на одиницю кожні 4 мікросекунди. Завдяки номерам послідовностей, пакети, що затрималися в мережі та доставлені пізніше, не сприймаються як частина існуючого з'єднання.

Як вибирається номер послідовності? У 4.4BSD (і у більшості Berkeley реалізацій) при ініціалізації системи вихідний номер послідовності встановлюється в 1. Подібна практика засуджується вимогою до хостів Host Requirements RFC. Потім ця величина збільшується на 64000 кожні півсекунди і повертається значення 0 через кожні 9,5 годин. (Це відповідає лічильнику, який збільшується на одиницю кожні 8 мікросекунд, а не кожні 4 мікросекунди.) Крім того, щоразу, коли встановлюється з'єднання, ця змінна збільшується на 64000.

Проміжок в 4,1 секунд між сегментами 3 і 4 відповідає часу між встановленням з'єднання і введенням команди quit для telnet, щоб розірвати з'єднання.

Протокол розриву з'єднання

Для того щоб встановити з'єднання, необхідно 3 сегменти, а для того, щоб розірвати - 4. Це пояснюється тим, що TCP з'єднання може бути наполовину закритому стані. Так як TCP з'єднання повнодуплексне (дані можуть пересуватися в кожному напрямку незалежно від іншого напрямку), кожен напрямок має бути закрито незалежно від іншого. Правило полягає в тому, що кожна сторона повинна надіслати FIN, коли передача даних завершена. Коли TCP приймає FIN, він повинен повідомити, що віддалена сторона розриває з'єднання і припиняє передачу даних у цьому напрямку. FIN зазвичай відправляється в результаті того, що програма була закрита.

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

Сегмент номер 4 на малюнку 18.3 призводить до закриття з'єднання та надсилається, коли Telnet клієнт припиняє роботу. Це відбувається коли ми вводимо quit. При цьому TCP клієнт змушений надіслати FIN, закриваючи потік даних від клієнта до сервера.

Коли сервер отримує FIN, він відправляє назад ACK із прийнятим номером послідовності плюс один (сегмент 5). На FIN витрачається один номер послідовності, як і на SYN. У цей момент TCP сервер також доставляє додатку ознаку кінця файлу (end-of-file) (щоб вимкнути сервер). Потім сервер закриває своє з'єднання, що змушує TCP послати FIN (сегмент 6), який клієнт повинен підтвердити (ACK), збільшивши на одиницю номер прийнятої послідовності (сегмент 7).

На малюнку 18.4 показаний типовий обмін сегментами під час закриття з'єднання. Номери послідовності опушені. На цьому малюнку FIN надсилаються через те, що програми закривають свої з'єднання, тоді як ACK для цих FIN генерується автоматичним програмним забезпеченням TCP.

З'єднання зазвичай встановлюються клієнтом, тобто перший SYN рухається від клієнта до сервера. Проте будь-яка сторона може активно закрити з'єднання (надіслати перший FIN). Часто, однак, саме клієнт визначає, коли з'єднання має бути розірвано, оскільки процес клієнта в основному управляється користувачем, який вводить щось подібне "quit", щоб закрити з'єднання. На малюнку 18.4 ми можемо поміняти місцями мітки, наведені зверху малюнка, назвавши ліву сторону сервером, а правий бікклієнтом. Однак навіть у цьому випадку все працюватиме саме так, як показано на малюнку. (Перший приклад у розділі "Простий приклад" глави 14, наприклад, показував, як сервер часу закриває з'єднання.)

Рисунок 18.4 Звичайний обмін сегментами під час закриття з'єднання.

Звичайний висновок tcpdump

Так як завдання відсортувати величезну кількість номерів послідовності досить складна, у виведенні програми tcpdump містяться повні номери послідовності тільки для сегментів SYN, а всі наступні номери послідовностей показані як відносне зміщення від вихідних номерів послідовності. (Для того щоб отримати висновок, наведений на малюнку 18.1, ми повинні були вказати опцію -S.) Звичайний висновок tcpdump, який відповідає малюнку 18.1, показаний на малюнку 18.5.

1 0.0 svr4.1037 > bsdi.discard: S 1415531521:1415531521(0)
win 4096
2 0.002402 (0.0024) bsdi.discard > svr4.1037: S 1823083521:1823083521(0)
ack 1415531522
win 4096
3 0.007224 (0.0048) svr4.1037 > bsdi.discard: . ack 1 win 4096
4 4.155441 (4.1482) svr4.1037 > bsdi.discard: F 1:1 (0) ack 1 win 4096
5 4.156747 (0.0013) bsdi.discard > svr4.1037: . ack 2 win 4096
6 4.158144 (0.0014) bsdi.discard > svr4.1037: F 1:1 (0) ack 2 win 4096
7 4.180662 (0.0225) svr4.1037 > bsdi.discard: . ack 2 win 4096

Рисунок 18.5 Звичайний висновок команди tcpdump, що відповідає встановленню та розриву з'єднання.

Якщо у нас не буде необхідності показувати повні номери послідовності, ми будемо використовувати цю форму виведення у всіх наступних прикладах.

Тайм-аут під час встановлення з'єднання

Існує кілька причин, через які не може бути встановлено з'єднання. Наприклад, хост (сервер) вимкнено. Щоб зімітувати подібну ситуацію, ми виконали команду telnet після того, як від'єднали Ethernet кабель від сервера. На малюнку 18.6 показано виведення команди tcpdump.

1 0.0 bsdi.1024 > svr4.discard: S 291008001:291008001(0)
win 4096
2 5.814797 (5.8148) bsdi.1024 >
win 4096
3 29.815436 (24.0006) bsdi.1024 > svr4.discard: S 291008001:291008001(0)
win 4096

Рисунок 18.6 Виведення команди tcpdump для встановлення з'єднання, яке було припинено за тайм-аутом.

У цьому висновку необхідно звернути увагу, як часто TCP клієнт відправляє SYN, намагаючись встановити з'єднання. Другий сегмент посилається через 5,8 секунд після першого, а третій посилається через 24 секунд після другого.

Слід зазначити, що цей приклад був запущений приблизно через 38 хвилин після того, як клієнт був перезавантажений. Тому відповідний вихідний номер послідовності дорівнює 291008001 (приблизно 38х60х6400х2). На початку глави ми сказали, що типові системи Berkeley встановлюють вихідний номер послідовності в 1, а потім збільшують його на 64 000 кожні півсекунди.

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

Однак на малюнку 18.6 не показано, скільки часу TCP клієнт здійснював повторні передачі, перш ніж відмовитися від спроби. Для того, щоб подивитися це тимчасові значення, ми повинні виконати команду telnet наступним чином:

bsdi % date; telnet svr4 discard; date
Thu Sep 24 16:24:11 MST 1992
Trying 192.82.148.2...
telnet: Необхідний для підключення до remote host: Connection timed out
Thu Sep 24 16:25:27 MST 1992

Час складає 76 секунд. Більшість систем Berkeley встановлюють межу часу 75 секунд, за цей час має бути встановлене нове з'єднання. У розділі "Приклад RTT" глави 21 ми побачимо, що третій пакет, надісланий клієнтом, буде відкинуто за тайм-аутом приблизно о 16:25:29, тобто через 48 секунд після того, як його було відправлено, при цьому клієнт не припинить свої спроби за 75 секунд.

Перший тайм-аут

На малюнку 18.6 слід звернути увагу на те, що перший тайм-аут, 5,8 секунд, близький до 6 секунд, однак не дорівнює 6 секунд, тоді як другий тайм-аут практично точно дорівнює 24 секунд. Було виконано ще десять подібних тестів, причому у кожному їх значення першого тайм-ауту коливалося в діапазоні від 5,59 секунди до 5,93 секунди. Другий тайм-аут, однак, завжди був 24,00 секунд.

Це пояснюється тим, що BSD реалізації TCP запускають таймер кожні 500 мілісекунд. Цей 500 мілісекундний таймер використовується для різних TCP тайм-аутів, всі вони будуть описані в наступних розділах. Коли ми вводимо команду telnet, встановлюється вихідний 6-секундний таймер (12 тиків годин), однак він може закінчитися в будь-якому місці між 5,5 та 6 секундами. На малюнку 18.7 показано, як це відбувається.

Малюнок 18.7 500-мілісекундний таймер TCP.

Так як таймер встановлений у 12 тиків, перше зменшення таймера може відбутися між 0 та 500 мілісекунд після його встановлення. З цього моменту таймер зменшується приблизно кожні 500 мілісекунд, проте перший період може бути різним. (Ми використовуємо слово "приблизно", тому що час, коли TCP отримує управління кожні 500 мілісекунд, зразкове, тому що може пройти інше переривання, яке оброблятиметься ядром.)

Коли цей 6-секундний таймер закінчиться на тику поміченому 0 на малюнку 18.7, таймер встановлюється в 24 секунди (48 тиків). Цей наступний таймер дорівнює 24 секундам, оскільки він був встановлений в той момент часу, коли 500-мілісекундний таймер TCP був викликаний ядром, а не користувачем.

Поле типу сервісу

На малюнку 18.6 бачимо вираз . Це поле типу сервісу (TOS - type-of-service) в IP-датаграмі (рисунок 3.2). Telnet клієнт у BSD/386 встановлює це поле таким чином, щоб отримати мінімальну затримку.

Максимальний розмір сегмента

Максимальний розмір сегмента (MSS) – це найбільша порція даних, яку TCP надішле на віддалений кінець. Коли встановлюється з'єднання, кожна сторона може оголосити свій MSS. Значення, які ми бачили, були 1024. IP датаграма, яка вийде в результаті, зазвичай на 40 байт більше: 20 байт відводиться під заголовок TCP і 20 байт під IP заголовок.

У деяких публікаціях йдеться, що ця опція встановлюється "за домовленістю". Насправді домовленість у цьому випадку не використовується. Коли з'єднання встановлюється, кожна сторона повідомляє MSS, якою вона збирається приймати. ( Опція MSS може бути використана тільки в сегменті SYN.) Якщо одна сторона не приймає опцію MSS від іншої сторони, використовується розмір за замовчуванням в 536 байт. (У цьому випадку, при 20-байтному IP заголовку та 20-байтному TCP заголовку, розмір IP датаграми становитиме 576 байт.)

У загальному випадку, чим більше MSS тим краще, поки не відбувається фрагментація. (Це не завжди вірно. Зверніться до малюнку 24.3 та малюнку 24.4 , щоб переконатися в цьому.) Великі розмірисегмента дозволяють надіслати більше даних у кожному сегменті, що зменшує відносну вартість IP та TCP заголовків. Коли TCP відправляє SYN сегмент, або коли локальна програма хоче встановити з'єднання, або коли прийнятий запит на з'єднання від віддаленого хоста, може бути встановлено значення MSS, що дорівнює MTU вихідного інтерфейсу мінус розмір фіксованих TCP і IP заголовків. Для Ethernet MSS може сягати 1460 байт. При використанні інкапсуляції IEEE 802.3 (глава 2, розділ "Ethernet та IEEE 802 інкапсуляція") MSS може бути до 1452 байт.

Значення 1024, яке ми бачимо в цьому розділі, відповідає з'єднанням, у яких беруть участь BSD/386 і SVR4, тому що більшість BSD реалізацій вимагає, щоб MSS було кратно 512. Інші системи, такі як SunOS 4.1.3, Solaris 2.2 та AIX 3.2 .2, оголошують MSS, що дорівнює 1460, коли обидві сторони знаходяться на одному Ethernet. Розрахунки, наведені в [Mogul 1993], показують, що MSS рівний 1460 забезпечують кращу продуктивністьна Ethernet, ніж MSS дорівнює 1024.

Якщо IP адреса призначення "не локальна", MSS зазвичай встановлюється за замовчуванням - 536. Чи є локальним або нелокальним кінцевий пункт призначення можна наступним чином. Пункт призначення, IP адреса якого має той самий ідентифікатор мережі і ту саму маску підмережі, що і у відправника є локальним; пункт призначення, IP-адреса якого повністю відрізняється від ідентифікатора мережі, є нелокальною; пункт призначення з тим самим ідентифікатором мережі, однак з іншою маскою підмережі, може бути як локальним, так і нелокальним. Більшість реалізацій надають опцію конфігурації (додаток E та малюнок Е.1), яка дозволяє системному адміністратору вказати, які підмережі є локальними, а які є нелокальними. Установка цієї опції визначає максимальний анонсований MSS (який за величиною може досягати MTU вихідного інтерфейсу), інакше використовується значення за промовчанням 536.

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

Уявіть наш хост slip, який має SLIP канал із MTU рівним 296, підключеним до маршрутизатора bsdi. На малюнку 18.8 показані ці системи та хост sun.

Рисунок 18.8 TCP з'єднання від sun до slip та значення MSS.

Ми встановили TCP з'єднання від sun до slip та переглянули сегменти з використанням tcpdump. На малюнку 18.9 показано лише встановлення з'єднання (оголошення розміру вікна видалено).

1 0.0 sun.1093 > slip.discard: S 517312000:517312000(0)

2 0.10 (0.00) slip.discard > sun.1093: S 509556225:509556225(0)
ack 517312001
3 0,10 (0,00) sun.1093 > slip.discard: . ack 1

Рисунок 18.9 Виведення tcpdump для встановлення з'єднання від sun до slip.

Тут важливо звернути увагу на те, що Sun не може послати сегмент з порцією даних більше ніж 256 байт, так як він отримав MSS рівний 256 (рядок 2). Більше того, тому що slip знає що MTU вихідного інтерфейсу дорівнює 296, навіть якщо sun оголосить MSS рівний 1460, він ніколи не зможе послати більше ніж 256 байт даних, щоб уникнути фрагментації. Проте, система може надіслати даних менше, ніж MSS оголошений віддаленою стороною.

Уникнути фрагментації таким чином можна тільки якщо хост безпосередньо підключений до мережі з MTU менше ніж 576. Якщо обидва хости підключені до Ethernet і обидва анонсують MSS 536, однак проміжна мережа має MTU 296, буде здійснена фрагментація. Єдиний спосіб уникнути цього – скористатися механізмом визначення транспортного MTU (глава 24, розділ "Визначення транспортного MTU").

Наполовину закритий TCP

TCP надає можливість одному учаснику з'єднання припинити передачу даних, але все ще отримувати дані від віддаленої сторони. Це називається наполовину закритий TCP. Як ми вже згадували раніше, деякі програми можуть користуватися цією можливістю.

Щоб використовувати цю характеристику програмного інтерфейсу, необхідно надати можливість додатку сказати: "Я закінчило передачу даних, тому посилаю ознаку кінця файлу (end-of-file) (FIN) на віддалений кінець, проте я все ще хочу отримувати дані з віддаленого кінця до тих доки він мені не надішле ознаку кінця файлу (end-of-file) (FIN)."

Сокети API підтримують напівзакритий режим, якщо програма викличе shutdown з другим аргументом, рівним 1 замість виклику close. Більшість програм, однак, розривають з'єднання в обох напрямках викликом close.

На малюнку 18.10 показано стандартний сценарій для напівзакритого TCP. Ми показали клієнта з лівого боку, він ініціює напівзакритий режим, але це може зробити будь-яка сторона. Перші два сегменти однакові: FIN від ініціатора, за ним слідує ACK і FIN від приймаючого. Однак далі сценарій відрізнятиметься від того, що наведено на малюнку 18.4, тому що сторона, яка прийняла наказ "напівзакрити", може все ще надсилати дані. Ми показали лише один сегмент даних, за яким слідує ACK, проте в цьому випадку може бути надіслана будь-яка кількість сегментів даних. (Ми розповімо більш докладно про обмін сегментами даних та підтвердженнями в розділі 19.) Коли кінець, який отримав наказ "напівзакрити", здійснив передачу даних, він закриває свою частину з'єднання, в результаті чого посилається FIN, при цьому ознака кінця файлу доставляється додатку, яке ініціювало "напівзакритий" режим. Коли другий FIN підтверджено, з'єднання вважається повністю закритим.

Малюнок 18.10 TCP у напівзакритому режимі.

Для чого можна використовувати напівзакритий режим? Одним із прикладів може бути команда Unix rsh(1), яка виконує команду в іншій системі. Команда

sun % rsh bsdi sort< datafile

запустить команду sort на хості bsdi, причому стандартне введення команди rsh читатиметься з файлу з ім'ям datafile. Команда rsh створює TCP з'єднання між собою та програмою, яка буде виконана на віддаленому хості. Потім rsh функціонує досить просто: команда копіює стандартне введення (datafile) в з'єднання і копіює зі з'єднання стандартний висновок (наш термінал). На малюнку 18.11 показано, як це відбувається. (Ми пам'ятаємо, що TCP з'єднання повнодуплексне.)

Рисунок 18.11 Команда: rsh bsdi sort< datafile.

На віддаленому хості bsdi сервер rshd виконує програму sort таким чином, що її стандартне введення та стандартне виведення направлені в TCP з'єднання. У розділі 14 наводиться докладний опис структури процесу Unix, який бере участь тут, проте нас цікавить, як використовується з'єднання TCP і напівзакритий режим TCP.

Програма sort не може почати генерацію виведення до тих пір, поки все її введення не буде прочитане. Усі вихідні дані, що надходять з'єднання від клієнта rsh на сервер sort, надсилаються у файл, який має бути відсортований. Коли досягається позначка кінця файлу у введенні (datafile), клієнт rsh здійснює напівзакриття TCP з'єднання. Потім сервер sort приймає мітку кінця файлу зі свого стандартного введення (з'єднання TCP), сортує файл і пише результат у свій стандартний висновок (з'єднання TCP). Клієнт rsh продовжує читати TCP з'єднання на своєму кінці, копіюючи відсортований файл у свій стандартний висновок.

Без використання наполовину закритого режиму потрібна будь-яка додаткова техніка, яка дозволить клієнту повідомити сервер, що він закінчив посилку даних, проте клієнту все ще дозволено отримувати дані від сервера. Альтернативно необхідно використовувати дві сполуки, проте переважно використання напівзакритого режиму.

Діаграма станів передачі TCP

Ми описали кілька правил встановлення та розриву TCP з'єднання. Ці правила зібрані у діаграму станів передачі, що наведено малюнку 18.12.

Слід зазначити, що це діаграма - діаграма стандартних станів. Ми помітили звичайну передачу клієнта суцільними жирними стрілками, а звичайну передачу сервера - жирними стрілками.

Дві передачі, які ведуть стану ВСТАНОВЛЕНО ( ESTABLISHED), відповідають відкриттю з'єднання, а дві передачі, які ведуть стану ВСТАНОВЛЕНО (ESTABLISHED), відповідають розриву з'єднання. Стан ВСТАНОВЛЕНО (ESTABLISHED) настає у той момент, коли з'являється можливість здійснити передачу даних між двома сторонами в обох напрямках. У наступних розділах буде описано, що відбувається у цьому стані.

Ми об'єднали чотири квадратики в лівій нижній частині діаграми всередині пунктирної рамки і помітили їхнє "активне закриття" (active close). Два інших квадратики (ЧЕКАННЯ_ЗАКРИТТЯ - CLOSE_WAIT і ОСТАННЕ_ПІДТВЕРДЖЕННЯ - LAST_ACK) об'єднані пунктирною рамкою і позначені як "пасивне закриття" (passive close).

Назви 11-ти станів (ЗАКРИТО - CLOSED, СЛУХАЄ - LISTEN, SYN_ВІДПРАВЛЕНИЙ - SYN_SENT, і так далі) на цьому малюнку обрані таким чином, щоб відповідати станам, які виводить команда netstat. Імена ж netstat, своєю чергою, практично ідентичні іменам, описаним у RFC 793. Стан ЗАКРИТО (CLOSED) насправді перестав бути станом, проте є стартової і кінцевою точкою для діаграми.

Зміна стану від СЛУХАЄ (LISTEN) до SYN_ВІДПРАВЛЕНИЙ (SYN_SENT) теоретично можлива, проте не підтримується в реалізаціях Berkeley.

А зміна стану від ОТРИМАНИЙ_SYN ( SYN_RCVD) назад до СЛУХАЄ (LISTEN) можлива тільки в тому випадку, якщо в стан ОТРИМАНИЙ_SYN (SYN_RCVD) увійшли зі стану СЛУХАЄ (LISTEN) (це звичайний сценарій), а не зі стану SYN відкриття). Це означає, що якщо ми здійснили пасивне відкриття (увійшли в стан СЛУХАЄ - LISTEN), отримали SYN, послали SYN з ACK (увійшли в стан ОТРИМАНИЙ_SYN - SYN_RCVD) і потім отримали скидання замість ACK, кінцева точка повертається в стан СЛУХАЄ ( очікує на прибуття іншого запиту на з'єднання.

Рисунок 18.12 Діаграма змін стану TCP.

На малюнку 18.13 показано звичайне встановлення та закриття TCP з'єднання. Також детально описані різні станичерез які проходять клієнт і сервер.

Малюнок 18.13 Стан TCP, відповідний звичайному відкриттюта розриву з'єднання.

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

Вам слід простежити зміни станів на малюнку 18.13 з використанням датаграми зміни станів, наведеної на малюнку 18.12, що дозволить зрозуміти, чому здійснюється та чи інша зміна стану.

Стан очікування 2MSL

Стан ЧАС_ОЧІКУВАННЯ (TIME_WAIT) також іноді називається станом очікування 2MSL. У кожному реалізації вибирається значення максимального часу життя сегмента ( MSL - maximum segment lifetime) . Це максимальний час, протягом якого сегмент може існувати в мережі перед тим, як він буде відкинутий. Ми знаємо, що цей час обмежений, оскільки TCP сегменти передаються за допомогою IP-датаграм, а кожна IP-датаграма має поле TTL, яке обмежує час її життя.

RFC 793 [ Postel 1981c] вказує, що MSL має дорівнювати 2 хвилинам. У різних реалізаціях ця величина має значення 30 секунд, 1 або 2 хвилини.

У розділі 8 говорилося, що життя IP датаграми обмежується кількістю пересилок, а чи не таймером.

При використанні MSL діють такі правила: коли TCP здійснює активне закриття і посилає останній сегмент, що містить підтвердження (ACK), з'єднання має залишитися в стані TIME_WAIT на час, що дорівнює двом MSL. Це дозволяє TCP повторно надіслати останній ACK у разі, якщо перший ACK втрачено (у разі віддалена сторона відпрацює тайм-аут і повторно передасть свій кінцевий FIN).

Інше призначення очікування 2MSL полягає в тому, що поки TCP з'єднання знаходиться в очікуванні 2MSL, пара сокетів, виділена для цього з'єднання (IP-адреса клієнта, номер порту клієнта, IP-адреса сервера і номер порту сервера), не може бути повторно використана. Це з'єднання може бути використане повторно лише коли закінчиться час очікування 2MSL.

На жаль, більшість реалізацій (Berkeley одна з них) підкоряються більш жорстким вимогам. За замовчуванням локальний номер порту не може бути повторно використаний, доки цей номер порту є локальним номером порту пари сокетів, який перебуває у стані очікування 2MSL. Нижче розглянемо приклади загальних вимог.

Деякі реалізації та API надають засоби, які дозволяють обійти ці обмеження. З використанням API сокет може бути вказано опцію сокету SO_REUSEADDR. Вона дозволяє призначати номер локального порту, який знаходиться в стані 2MSL, проте ми побачимо, що правила TCP не дозволяють цьому номеру порту бути використаним в з'єднанні, яке знаходиться в стані очікування 2MSL.

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

Як ми вже показали малюнку 18.13, зазвичай клієнт здійснює активне закриття і входить у режим TIME_WAIT. Сервер зазвичай здійснює пасивне закриття та не проходить через режим TIME_WAIT. Можна зробити висновок, що якщо ми вимкнемо клієнта і негайно перестартуємо його, цей новий клієнтне зможе використовувати той самий локальний номер порту. У цьому немає жодної проблеми, оскільки клієнти зазвичай використовують порти, що динамічно призначаються, і не піклуються, який динамічно призначається порт використовується в даний час.

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

Спостерігати подібний сценарій можна з використанням програми sock. Ми стартували сервер, приєднали до нього клієнта, а потім вимкнули сервер:

Sun % sock-v-s 6666
(запускаємо клієнта на bsdi, який приєднається до цього порту)
connection on 140.252.13.33.6666 from140.252.13.35.1081
^?
sun % sock-s 6666і намагаємося негайно перестартувати сервер на той самий порт

sun % netstatспробуємо перевірити стан з'єднання
Active Internet сonnections
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp 0 0 sun.6666 bsdi.1081 TIME_WAIT
безліч рядків видалено

Коли ми намагаємося перестартувати сервер, програма видає повідомлення про помилку, що вказує на те, що вона не може захопити свій відомий номер порту, тому що він вже використовується (перебуває в стані очікування 2MSL).

Потім ми негайно виконуємо netstat, щоб переглянути стан з'єднання і перевірити, чи воно дійсно знаходиться в стані TIME_WAIT.

Якщо ми будемо продовжувати спроби перестартувати сервер і подивимося час, коли це вдасться, можемо обчислити значення 2MSL. Для SunOS 4.1.3, SVR4, BSD/386 і AIX 3.2.2 перестартування сервера займе 1 хвилину, що означає, що MSL дорівнює 30 секунд. У Solaris 2.2 це перестартування сервера займає 4 хвилини, це означає, що MSL дорівнює 2 хвилинам.

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

Sun % sock-v bsdi echoстартуємо клієнт, який приєднується до сервера echo
connected on 140.252.13.33.1162 to 140.252.13.35.7
hello thereдрукуємо цей рядок
hello there вона відбивається луною від сервера
^D
sun % sock -b1162 bsdi echo
can't bind local address: Address already in use

При першому запуску клієнта була вказана опція -v, яка дозволяє переглянути, який використовується локальний номер порту (1162). При другому запуску клієнта була вказана опція -b, яка повідомляє клієнту про необхідність призначити самому собі номер локального порту 1162. Як ми й очікували, клієнт не може цього зробити, тому що цей номер порту є частиною з'єднання, яке знаходиться в стані 2MSL.

Тут необхідно згадати про одну особливість стану очікування 2MSL, до якої ми повернемося в розділі 27, коли розповідатимемо про протокол передачі файлів (FTP - File Transfer Protocol). Як згадувалося раніше, може очікування 2MSL залишається пара сокетів (що складається з локального IP адреси, локального порту, віддаленого IP адреси і віддаленого порту). Однак, безліч реалізацій дозволяють процесу повторно використовувати номер порту, який є частиною з'єднання, що знаходиться в режимі 2MSL (зазвичай з використанням опції SO_REUSEADDR) TCP не може дозволити створити нове з'єднання з тією ж парою сокет. Це можна довести за допомогою наступного експерименту:

Sun % sock-v-s 6666старт сервера, що слухає порт 6666
(запускаємо клієнта на bsdi, який приєднується до цього порту)
connection on 140.252.13.33.6666 від 140.252.13.35.1098
^? вводимо символ переривання, щоб вимкнути сервер
sun % sock -b6666 bsdi 1098стартуємо клієнта з локальним портом 6666
can't bind local address: Address already in use
sun % sock -A -b6666 bsdi 1098намагаємося знову, цього разу з опцією -A
active open error: Address already in use

Вперше ми запустили нашу програму sock як сервер на порт 6666 та приєднали до нього клієнта з хоста bsdi. Номер порту клієнта 1098, що динамічно призначається. Ми вимкнули сервер, таким чином, він здійснив активне закриття. При цьому 4 параметри - 140.252.13.33 (локальна IP адреса), 6666 (локальний номер порту), 140.252.13.35 (віддалена IP адреса) та 1098 ( віддалений номерпорту) на сервері потрапляють у стан 2MSL.

Вдруге ми запустили цю програму в якості клієнта, вказавши локальний номер порту 6666, при цьому була спроба приєднатися до хоста bsdi на порт 1098. При спробі повторно використовувати локальний порт 6666 була згенерована помилка, оскільки цей порт знаходиться в стані 2MSL.

Щоб уникнути цієї помилки, ми запустили програму знову, вказавши опцію -A, яка активізує опцію SO_REUSEADDR. Це дозволило програмі призначити собі номер порту 6666, однак було отримано помилку, коли програма спробувала здійснити активне відкриття. Навіть якщо програма зможе призначити собі номер порту 6666, вона зможе створити з'єднання з портом 1098 на хості bsdi, оскільки пара сокетів, визначальна це з'єднання, перебуває у стані очікування 2MSL.

Що, якщо ми спробуємо встановити з'єднання з іншого хоста? По-перше, ми повинні перестартувати сервер на sun з прапором -A, тому що порт, який йому необхідний (6666), є частиною з'єднання, що знаходиться в стані очікування 2MSL:

Sun % sock-A-s 6666стартуємо сервер, що слухає порт 6666

Потім, перед тим, як стан очікування 2MSL закінчиться на sun, ми стартуємо клієнта на bsdi:

bsdi % sock -b1098 sun 6666
connected on 140.252.13.35.1098 to 140.252.13.33.6666

На жаль, це працює! Це недолік TCP специфікації, проте підтримується більшістю реалізацій Berkeley. Ці реалізації сприймають прибуття запиту на нове з'єднання для з'єднання, яке знаходиться в стані TIME_WAIT, якщо новий номер послідовності більший ніж останній номер послідовності, використаний у попередньому з'єднанні. У цьому випадку ISN для нового з'єднання встановлюється рівним останньому номеру послідовності попереднього з'єднання плюс 128000. Додаток до RFC 1185 показує можливі недоліки подібної технології.

Ця характеристика реалізації дозволяє клієнту і серверу повторно використовувати ті самі номери порту для успішного відновлення того ж з'єднання, в тому випадку, однак, якщо сервер не здійснив активне закриття. Ми побачимо інший приклад стану очікування 2MSL на малюнку 27.8, коли обговорюватимемо FTP. Також зверніться до цього розділу.

Тихий час концепції

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

Що якщо хост з портами в стані 2MSL вийшов з ладу, перезавантажився під час MSL і негайно встановив нові з'єднання з використанням тих самих локальних і віддалених IP-адрес і номерів портів, що відповідають локальним портам, які були в стані 2MSL перед поломкою? У цьому випадку сегменти, що запізнилися, із сполуки, яка існувала перед поломкою, можуть бути помилково інтерпретовані як належать новому з'єднанню, створеному після перезавантаження. Це може статися незалежно від того, який вихідний номер послідовності вибрано після перезавантаження.

Для захисту від таких небажаних сценаріїв RFC 793 вказує, що TCP не повинен створювати нові з'єднання до закінчення MSL після завантаження. Це називається тихий час(Quiet time).

У деяких реалізаціях хости очікують навіть довше, ніж час MSL після перезавантаження.

Стан ОЧІКУВАННЯ_І_ПІДТВЕРДЖЕННЯ_FIN (FIN_WAIT_2)

У стані FIN_WAIT_2 ми надсилаємо наш FIN, а віддалена сторона підтверджує його. Якщо ми не знаходимося в стані напівзакритого з'єднання, то очікуємо від програми на віддаленому кінці, що воно впізнає прийом ознаки кінця файлу і закриє свою сторону з'єднання, причому надішле нам FIN. Тільки коли процес на віддаленому кінці здійснить закриття, наша сторона перейде з режиму FIN_WAIT_2 в режим TIME_WAIT.

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

Більшість Berkeley реалізацій запобігають такому вічному очікуванню в стані FIN_WAIT_2 наступним чином. Якщо програма, яка здійснила активне закриття, здійснила повне закриття, а не напівзакриття, що вказує на те, що воно очікує на прийом даних, в цьому випадку встановлюється таймер. Якщо з'єднання не використовується протягом 10 хвилин плюс 75 секунд, TCP переводить з'єднання в режим ЗАКРИТО ( CLOSED). У коментарях йдеться про те, що подібна характеристика суперечить специфікації протоколу.

Сегменти скидання (Reset)

Ми згадували, що у TCP заголовку існує біт, званий RST, що означає " скидання " (reset). У загальному випадку сигнал "скидання" (reset) посилається TCP у тому випадку, якщо сегменти, що прибувають, не належать зазначеному з'єднанню. (Ми використовуємо термін "вказане з'єднання" (referenced connection), який позначає з'єднання, що ідентифікується IP адресою призначення та номером порту призначення, а також IP адресою джерела та номером порту джерела. У RFC 793 це називається "сокет".)

Запит про з'єднання на неіснуючий порт

Найбільш загальний випадок, при якому генерується скидання (reset), це коли запит про з'єднання прибуває і при цьому немає процесу, який слухає порт призначення. У випадку UDP, як ми бачили в розділі "ICMP помилка недоступності порту" глави 6, якщо датаграма прибуває на порт призначення, що не використовується - генерується помилка ICMP про недоступність порту. TCP натомість використовує скидання.

Ми наведемо простий приклад з використанням клієнта Telnet, вказавши номер порту, який не використовується на пункті призначення:

Bsdi% telnet svr4 20000порт 20000 не використовується
Trying 140.252.13.34...
telnet: Зовнішній зв'язок remote host: Connection refused

Повідомлення про помилку видається клієнту Telnet негайно. На малюнку 18.14 показаний обмін пакетами, що відповідає цій команді.

1 0.0 bsdi.1087 > svr4.20000: S 297416193:297416193(0)
win 4096
2 0.003771 (0.0038) svr4.20000 > bsdi.1087: R 0:0 (0) ack 297416194 win 0

Малюнок 18.14 Генерація скидання під час спроби відкрити з'єднання на неіснуючий порт.

Значення, які нам необхідно детальніше розглянути на цьому малюнку, це поле номера послідовності та поле номера підтвердження у скиданні. Так як біт підтвердження (ACK) не був встановлений в сегменті, що прибув, номер послідовності скидання встановлено в 0, а номер підтвердження встановлений у вхідний вихідний номер послідовності (ISN) плюс кількість байт даних в сегменті. Незважаючи на те, що в сегменті, що прибув, не присутній реальних даних, біт SYN логічно займає 1 байт в просторі номера послідовності; таким чином, у цьому прикладі номер підтвердження в скиданні встановлюється ISN плюс довжина даних (0) плюс один SYN біт.

Розрив з'єднання

У розділі цього розділу ми бачили, що звичайний метод, який використовується для розриву з'єднання, полягає в тому, що одна із сторін посилає FIN. Іноді це називається правильним звільненням (orderly release), оскільки FIN надсилається після того, як усі дані, раніше поставлені в чергу, були відправлені, і зазвичай при цьому не відбувається втрата даних. Однак існує можливість перервати з'єднання, надіславши скидання (reset) замість FIN. Іноді це називається перерваючим звільненням (abortive release).

Подібний розрив з'єднання надає додатку дві можливості: (1) будь-які дані, що стоять у черзі - губляться, і скидання відправляється негайно, і (2) сторона, яка прийняла RST, може сказати, що віддалена сторона розірвала з'єднання замість того, щоб закрити його звичайним чином . Програмний інтерфейс(API), який використовується програмою, повинен надавати спосіб згенерувати подібне скидання замість нормального закриття.

Ми можемо подивитися, що відбувається у разі подібного розриву, використовуючи нашу програму sock. Сокети API надають цю можливість за допомогою опції сокету "затримки закриття" (linger on close) ( SO_LINGER). Ми вказали опцію -L з часом затримки, що дорівнює 0. Це означає, що замість звичайного FIN буде надіслано скидання, щоб закрити з'єднання. Ми підключимося до версії програми sock, яка виступає в ролі сервера, на svr4:

Bsdi% sock-L0 svr4 8888це клієнт; сервер показано далі
hello, worldвводимо один рядок, який буде відправлений на віддалений кінець
^Dвводимо символ кінця файлу, щоб вимкнути клієнта

На малюнку 18.15 показано виведення команди tcpdump для цього прикладу. (Ми видалили всі оголошення вікон у цьому малюнку, оскільки вони не впливають на наші міркування.)

1 0.0 bsdi.1099 > svr4.8888: S 671112193:671112193(0)

2 0.004975 (0.0050) svr4.8888 > bsdi.1099: S 3224959489:3224959489(0)
ack 671112194
3 0.006656 (0.0017) bsdi.1099 > svr4.8888: . ack 1
4 4.833073 (4.8264) bsdi.1099 > svr4.8888: P 1:14 (13) ack 1
5 5.026224 (0.1932) svr4.8888 > bsdi.1099: . ack 14
6 9.527634 (4.5014) bsdi.1099 > svr4.8888: R 14:14 (0) ack 1

Рисунок 18.15 Розрив з'єднання із використанням скидання (RST) замість FIN.

У рядках 1-3 показано нормальне встановлення з'єднання. У рядку 4 надсилається рядок даних, який ми надрукували (12 символів плюс Unix символ нового рядка), та у рядку 5 приходить підтвердження про прийом даних.

Рядок 6 відповідає введеному символу кінця файлу (Control-D), за допомогою якого ми вимкнули клієнта. Оскільки ми вказали розрив замість звичайного закриття (опція командного рядка -L0), TCP на bsdi надішле RST замість звичайного FIN. RST сегмент містить номер послідовності та номер підтвердження. Також зверніть увагу на те, що сегмент RST не очікує відповіді з віддаленого кінця - він не містить підтвердження взагалі. Отримувач скидання перериває з'єднання та повідомляє додатку, що з'єднання було перервано.

Ми отримаємо таку помилку від сервера при такому обміні:

Svr4% sock-s 8888запускаємо як сервер, слухаємо порт 8888
hello, world це те, що відправив клієнт
read error: Connection reset by peer

Цей сервер читає з мережі та копіює у стандартний висновок все що отримав. Зазвичай він завершує свою роботу, отримавши ознаку кінця файлу від свого TCP, проте тут бачимо, що він отримав помилку при прибутті RST. Помилка це саме те, що ми очікували: з'єднання було розірвано одним із учасників з'єднання.

Визначення напіввідкритої сполуки

Вважається, що TCP з'єднання напіввідкрите, якщо одна сторона закрила або перервала з'єднання без попередження іншої сторони. Це може статися у будь-який час, якщо один із двох хостів вийде з ладу. Так як якийсь час не буде спроб передати дані по напіввідкритому з'єднанню, одна зі сторін буде працювати, допоки не визначить, що віддалена сторона виходила з ладу.

Ще одна причина, через яку може виникнути напіввідкрите з'єднання, полягає в тому, що на хості клієнта було вимкнено живлення, замість того, щоб погасити програму клієнта, а потім вимкнути комп'ютер. Це відбувається тоді, наприклад, клієнт Telnet запускається на PC, і користувачі вимикають комп'ютер в кінці робочого дня. Якщо під час вимкнення PC не здійснювалася передача даних, сервер будь-коли дізнається, що клієнт зник. Коли користувач приходить наступного ранку, включає свій PC і стартує новий клієнт Telnet, на хості сервера стартує новий сервер. Через це на хості сервера може з'явитися багато відкритих TCP з'єднань. (У розділі 23 ми побачимо спосіб, за допомогою якого один кінець TCP з'єднання може визначити, що інший зник. Це робиться з використанням TCP опції "залишайся в живих" (keepalive)).

Ми можемо легко створити напіввідкрите з'єднання. Запускаємо клієнта Telnet на bsdi і приєднуємося до сервера discard на svr4. Вводимо один рядок і дивимось з використанням tcpdump, як він проходить, а потім від'єднуємо Ethernet кабельвід хоста сервера та перезапускаємо його. Цим самим ми імітували вихід з ладу сервера. (Ми від'єднали Ethernet кабель перед перезавантаженням сервера, щоб той не послав FIN у відкрите з'єднання, що роблять деякі TCP модулі при вимкненні.) Після того як сервер перезавантажився, ми під'єднали кабель і спробували надіслати ще один рядок від клієнта на сервер. Так як сервер був перезавантажений і втратив усі дані про з'єднання, які існували до перезавантаження, він нічого не знає про з'єднання і не підозрює про те, якому з'єднанню належать сегменти, що прибули. У цьому випадку сторона TCP відповідає скиданням (reset).

Bsdi% telnet svr4 discardзапуск клієнта
Trying 140.252.13.34...
Connected to svr4.
Escape character is "^]".
hi thereцей рядок надіслано нормально
тут ми перезавантажили хост сервера
another lineу цьому місці було здійснено скидання (reset)
Connection closed by foreign host.

На малюнку 18.16 показано висновок tcpdump для цього прикладу. (Ми видалили з виведення оголошення вікон, інформацію про тип сервісу та оголошення MSS, оскільки вони не впливають на наші міркування.)

1 0.0 bsdi.1102 > svr4.discard: S 1591752193:1591752193(0)
2 0.004811 (0.0048) svr4.discard > bsdi.1102: S 26368001:26368001(0)
ack 1591752194
3 0.006516 (0.0017) bsdi.1102 > svr4.discard: . ack 1

4 5.167679 (5.1612) bsdi.1102 > svr4.discard: P 1:11 (10) ack 1
5 5.201662 (0.0340) svr4.discard > bsdi.1102: . ack 11

6 194.909929 (189.7083) bsdi.1102 > svr4.discard: P 11:25 (14) ack 1
7 194.914957 (0.0050) arp who-has bsdi tell svr4
8 194.915678 (0.0007) arp reply bsdi is-at 0:0:c0:6f:2d:40
9 194.918225 (0.0025) svr4.discard > bsdi.1102: R 26368002:26368002(0)

Рисунок 18.16 Скидання у відповідь на прихід сегмента даних при напіввідкритому з'єднанні.

У рядках 1-3 здійснюється нормальне встановлення з'єднання. У рядку 4 відправляється рядок "hi there" (це можна приблизно перекласти як "Гей ви, там") на discard сервер, у рядку 5 приходить підтвердження.

У цьому місці ми від'єднали кабель Ethernet від svr4, перезавантажили його і під'єднали кабель знову. Уся процедура зайняла приблизно 190 секунд. Потім ми надрукували наступний рядок введення клієнта ("another line"), і коли ми натиснули клавішу Return, рядок було відправлено на сервер (рядок 6 малюнку 18.16). При цьому була отримана відповідь від сервера, проте сервер був перезавантажений, його ARP кеш порожній, тому в рядках 7 і 8 ми бачимо ARP запит і відгук. Потім у рядку 9 було надіслано скидання (reset). Клієнт отримав скидання і видав, що з'єднання було перервано віддаленим хостом. (Останнє повідомлення виведення від клієнта Telnet не так інформативно, як могло б бути.)

Одночасне відкриття

Для двох додатків існує можливість здійснити активне відкриття одночасно. З кожної сторони має бути переданий SYN, і ці SYN повинні пройти мережею назустріч один одному. Також потрібно, щоб кожна сторона мала номер порту, який відомий іншій стороні. Це називається одночасним відкриттям (simultaneous open).

Наприклад, додаток на хості А має локальний порт 7777 здійснює активне відкриття на порт 8888 хоста В. Додаток на хості має локальний порт 8888 здійснює активне відкриття на порт 7777 хоста А.

Це не те саме що приєднання Telnet клієнта з хоста А на Telnet сервер на хості В, в той час коли Telnet клієнт з хоста В приєднується до Telnet сервера на хості А. У подібному сценарії обидва Telnet сервери здійснюють пасивне відкриття, а не активне, тоді як Telnet клієнти призначають собі номери портів, що динамічно призначаються, а не порти, які заздалегідь відомі для віддалених Telnet серверів.

TCP спеціально розроблений таким чином, щоб обробляти одночасне відкриття, при цьому результатом є одне з'єднання, а не два. (В інших сімействах протоколів, наприклад, у транспортному рівні OSI, у подібному випадку створюється дві сполуки, а не одна.)

Коли здійснюється одночасне відкриття, зміни станів протоколу відрізняються від тих, що показані на малюнку 18.13. Обидва кінця відправляють SYN в один і той же час, при цьому входять у стан SYN_ВІДПРАВЛЕНИЙ (SYN_SENT). Коли кожна сторона приймає SYN, стан змінюється на SYN_ПРИНЯТИЙ ( SYN_RCVD) (див. малюнок 18.12), і кожен кінець повторно відправляє SYN з підтвердженням того, що SYN прийнятий. Коли кожен кінець отримує SYN плюс ACK, стан змінюється на ВСТАНОВЛЕНО (ESTABLISHED). Зміни станів наведено малюнку 18.17.

Рисунок 18.17 Обмін сегментами у процесі одночасного відкриття.

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

Здійснити одночасне відкриття можливе, проте досить складно. Обидві сторони повинні бути стартовані приблизно в той же час, таким чином, щоб SYN перетнулися один з одним. У цьому випадку може допомогти великий час повернення між двома учасниками з'єднання, що дозволяє SYN перетнутися. Щоб отримати це, ми використовуємо як один учасник з'єднання хост bsdi, а інший хост vangogh.cs.berkeley.edu. Оскільки між ними знаходиться SLIP канал із додзвоном, час повернення має бути досить великим (кілька сотень мілісекунд), що дозволяє SYN перетнутися.

Один кінець (bsdi) призначає локальний порт 8888 (опція командного рядка -b) і здійснює активне відкриття на порт 7777 іншого хоста:

Bsdi% sock-v-b8888 vangogh.cs.berkeley.edu 7777
connected on 140.252.13.35.8888 to 128.32.130.2.7777
TCP_MAXSEG = 512
hello, worldвводимо цей рядок
and hi there цей рядок був надрукований на іншому кінці
connection closed by peer це висновок, коли було отримано FIN

Інший кінець був стартований приблизно в цей же час, він призначив собі номер локального порту 7777 і здійснив активне відкриття на порт 8888:

Vangogh % sock -v -b7777 bsdi.tuc.noao.edu 8888
connected on 128.32.130.2.7777 to 140.252.13.35.8888
TCP_MAXSEG = 512
hello, world це введено на іншому кінці
and hi thereми надрукували цей рядок
^Dі потім ввели символ кінця файлу EOF

Ми вказали прапорець -v у командному рядку програми sock, щоб перевірити IP адреси та номери портів для кожного кінця з'єднань. Цей прапор також друкує MSS, який використовується на кожному кінці з'єднання. Ми також надрукували як введення по одному рядку на кожному кінці, які були відправлені на віддалений кінець і надруковані там, щоб переконатися, що обидва хости "бачать" один одного.

На малюнку 18.18 показано обмін сегментами для цієї сполуки. (Ми видалили деякі нові опції TCP, що з'явилися у вихідних SYN, що прийшли від vangogh, яка працює під керуванням 4.4BSD. Ми опишемо ці нові опції в розділі цього розділу.) Зверніть увагу, що за двома SYN (рядки 1 і 2) йдуть два SYN з ACK (рядки 3 та 4). У цьому відбувається одночасне відкриття.

У рядку 5 показано введений рядок "hello, world", що йде від bsdi до vangogh з підтвердженням у рядку 6. Рядки 7 та 8 відповідають рядку "and hi there", що йде в іншому напрямку. У рядках 9-12 показано звичайне закриття з'єднання.

Більшість реалізацій Berkeley не підтримує одночасне відкриття коректно. У цих системах, якщо Ви можете досягти того, що SYN перетнуться, все закінчиться обміном сегментів, кожен з SYN і ACK, в обох напрямках. У більшості реалізацій який завжди здійснюється перехід стану SYN_SENT в стан SYN_RCVD, показаний малюнку 18.12.

1 0.0 bsdi.8888 > vangogh.7777: S 91904001:91904001(0)
win 4096
2 0.213782 (0.2138) vangogh.7777 >
win 8192
3 0.215399 (0.0016) bsdi.8888 > vangogh.7777: S 91904001:91904001(0)
ack 1058199042 win 4096

4 0.340405 (0.1250) vangogh.7777 > bsdi.8888: S 1058199041:1058199041(0)
ack 91904002 win 8192

5 5.633142 (5.2927) bsdi.8888 > vangogh.7777: P 1:14 (13) ack 1 win 4096
6 6.100366 (0.4672) vangogh.7777 > bsdi.8888: . ack 14 win 8192

7 9.640214 (3.5398) vangogh.7777 > bsdi.8888: P 1:14 (13) ack 14 win 8192
8 9.796417 (0.1562) bsdi.8888 > vangogh.7777: Додати замітку Редагувати zametkу | ack 14 win 4096

9 13.060395 (3.2640) vangogh.7777 > bsdi.8888: F 14:14 (0) ack 14 win 8192
10 13.061828 (0.0014) bsdi.8888 > vangogh.7777: Додати замітку Редагувати zametkу | ack 15 win 4096
11 13.079769 (0.0179) bsdi.8888 > vangogh.7777: F 14:14 (0) ack 15 win 4096
12 13.299940 (0.2202) vangogh.7777 > bsdi.8888: . ack 15 win 8192

Малюнок 18.18 Обмін сегментами при одночасному відкритті.

Одночасне закриття

Як ми сказали раніше, з одного боку (часто, але не завжди з боку клієнта) здійснюється активне закриття, при цьому посилається перший FIN. Також можливо для обох сторін здійснити активне закриття, оскільки протокол TCP дозволяє здійснити одночасне закриття (simultaneous close).

У термінах, наведених на малюнку 18.12, обидва кінці переходять від стану ВСТАНОВЛЕНО ( ESTABLISHED) до стану ОЧЕКАННЯ_FIN_1 ( FIN_WAIT_1) , коли програма видає сигнал до закриття. При цьому обидва посилають FIN, які можливо зустрінуться десь у мережі. Коли FIN прийнято, на кожному кінці відбувається перехід зі стану FIN_WAIT_1 в стан ЗАКРИВАЮ ( CLOSING) і з кожного боку надсилається завершальний ACK. Коли кожен кінець отримує завершальний ACK, стан змінюється TIME_WAIT. На малюнку 18.19 показано зміни станів.

Малюнок 18.19 Обмін сегментами у процесі одночасного закриття.

При одночасному закритті відбувається обмін такою кількістю пакетів, як і при звичайному закритті.

TCP заголовок може містити опції (рисунок 17.2). Єдині опції, визначені в оригінальній специфікації TCP, такі: кінець списку опцій, немає операції та максимальний розмір сегмента. Ми бачили в наших прикладах опцію MSS практично в кожному SYN сегменті.

Більш нові RFC, наприклад RFC 1323 визначають додаткові опції TCP, більшість з яких можна виявити тільки в пізніших реалізаціях. (Ми опишемо нові опції у розділі 24.) На малюнку 18.20 показаний формат поточних опцій TCP - тих, які описані в RFC 793 та RFC 1323.

Рисунок 18.20 TCP опції.

Кожна опція починається з 1-байтового типу (kind), який свідчить про тип опції. Опції, тип яких дорівнює 0 та 1, займають 1 байт. Інші опції мають довжину (len) байт, який слідує за байтом типу. Довжина - це повна довжина, що включає байти типу та довжини.

Опція "ні операції" (NOP) додана, щоб відправник міг заповнити поля, які мають бути кратні 4 байтам. Якщо ми встановимо TCP з'єднання від системи 4.4BSD, у початковому сегменті SYN за допомогою tcpdump можна побачити наступні опції:

Опція MSS встановлена ​​в 512, за нею слідує NOP, за нею слідує опція розміру вікна. Перша опція NOP використовується для того, щоб доповнити 3-байтову опцію розміру вікна до 4 байт. Так само, 10-байтова опція тимчасової марки передує двома NOP, щоб займати 12 байт.

Чотири інші опції, яким відповідає тип рівний 4, 5, 6 та 7, називаються опціями селективного ACK та луна опціями. Ми не показали їх на малюнку 18.20, тому що відлуння опції замінені опцією тимчасової марки, а селективні ACK, як визначено в даний час, все ще знаходяться в обговоренні і не були включені в RFC 1323. Треба зазначити, що пропозиція T/TCP для TCP транзакцій (розділ "T/TCP: розширення TCP для транзакцій" глави 24) вказує ще три опції з типами 11, 12 і 13.

Реалізація TCP сервера

У розділі "Модель Клієнт-Сервер" глави 1 ми сказали, більшість TCP серверів - конкурентні. Коли на сервер надходить запит про встановлення нового з'єднання, він приймає з'єднання та запускає новий процес, який обслуговуватиме нового клієнта. Залежно від операційної системи використовуються різні способи створення нового сервера. У Unix системах новий процес створюється з допомогою функції fork.

Нам необхідно обговорити, як TCP взаємодіє із конкурентними серверами. Хочеться відповісти на наступне запитання: як обробляються номери портів, коли сервер отримує запит на нове з'єднання від клієнта, і що станеться, якщо одночасно прибуде кілька запитів на з'єднання?

Номери портів сервера TCP

Ми можемо сказати, як TCP обробляє номери портів, розглянувши будь-який TCP сервер. Розглянемо сервер Telnet з використанням команди netstat. Наступний висновок наведено для системи, які не мають активних Telnet з'єднань. (Ми видалили всі рядки за винятком одного, який показує сервер Telnet.)

Sun % netstat -a -n -f inet
Active Internet connections (including servers)

tcp 0 0 *.23 *.* LISTEN

Прапор -a повідомляє про всі кінцеві точки мережі, а не тільки про які знаходяться в стані встановлено ( ESTABLISHED). Прапор -n друкує IP адреси в цифровому десятковому поданні, замість того щоб використовувати DNS для конвертування адрес в імена, і друкує цифрові номерипортів (наприклад, 23) замість друку імен сервісів (у разі Telnet). Опція -f inet повідомляє лише про кінцеві точки TCP і UDP.

Локальна адреса виводиться як *.23, де зірочка зазвичай називається символом підстановки чи метасимволом. Це означає, що вхідний запит про з'єднання (SYN) буде прийнято з будь-якого локального інтерфейсу. Якщо хост має кілька інтерфейсів, ми могли б вказати одну конкретну IP-адресу як локальну IP-адресу (один з IP-адрес хоста), і тільки запити на з'єднання, прийняті з цього інтерфейсу, будуть обслужені. (Ми побачимо, як це робиться, пізніше у цьому розділі.) Локальний порт дорівнює 23, це заздалегідь відомий порт для Telnet.

Віддалена адреса показана як *.*, це означає, що віддалена IP-адреса і віддалений номер порту поки не відомі, тому що кінцева точка знаходиться в стані СЛУХАЄ (LISTEN), очікуючи прибуття запиту на з'єднання.

Зараз ми стартуємо Telnet клієнта на хості slip (140.252.13.65), який приєднається до цього сервера. Тут наведено відповідні рядки виведення команди netstat:

Proto Recv-Q Send-Q Local Address Foreign Address (state)

tcp 0 0 *.23 *.* LISTEN

Перший рядок для порту 23 - це встановлене з'єднання (ESTABLISHED). Для цього з'єднання заповнені всі чотири елементи локальної та віддаленої адрес: локальна IP адреса і номер порту, і віддалена IP адреса і номер порту. Локальна IP-адреса відповідає інтерфейсу, на який прибув запит про з'єднання (Ethernet інтерфейс, 140.252.13.33).

Кінцева точка залишилася у стані LISTEN. Це кінцева точка, яку конкурентний сервер використовує для того, щоб приймати запити на з'єднання, які прийдуть в майбутньому. В даному випадку TCP модуль, що знаходиться в ядрі, створив нову кінцеву точку в стані ESTABLISHED, в момент, коли запит про з'єднання прибув і був прийнятий. Також зверніть увагу на те, що номер порту для з'єднання, яке знаходиться в стані ESTABLISHED, не змінився: він дорівнює 23, як і кінцевої точки, яка знаходиться в стані LISTEN.

Зараз ми стартуємо ще одного Telnet клієнта з того самого клієнта (slip) на цей сервер. Відповідний висновок команди netstat виглядатиме так:

Proto Recv-Q Send-Q Local Address Foreign Address (state)

tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED
tcp 0 0 *.23 *.* LISTEN

Зараз ми бачимо два встановлених (ESTABLISHED) з'єднання з того самого хоста на той же сервер. Обидва мають локальний номер порту 23. Це не проблема для TCP, так як номери віддалених портів різні. Вони повинні бути різні, тому що кожен Telnet клієнт використовує порт, що динамічно призначається, а з визначення динамічно призначається порту ми знаємо, що динамічно призначеним може бути тільки той порт, який не використовується в даний час на хості (slip).

Цей приклад показує, що TCP демультиплексує вхідні сегменти з використанням усіх чотирьох значень, які порівнюються з локальною та віддаленою адресами: IP адреса призначення, номер порту призначення, IP адреса джерела та номер порту джерела. TCP не може визначити, який процес отримав вхідний сегмент, переглядаючи лише номер порту призначення. Також тільки одна з трьох кінцевих точок на порту 23, яка знаходиться в стані LISTEN, приймає запити на з'єднання. Кінцеві точки, які перебувають у стані ESTABLISHED, що неспроможні приймати сегменти SYN, а кінцева точка, що у стані LISTEN, неспроможна приймати сегменти даних.

Зараз ми стартуємо ще одного клієнта Telnet із хоста solaris, який пройде через SLIP канал від sun, а не через Ethernet.

Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp 0 0 140.252.1.29.23 140.252.1.32.34603 ESTABLISHED
tcp 0 0 140.252.13.33.23 140.252.13.65.1030 ESTABLISHED
tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED
tcp 0 0 *.23 *.* LISTEN

Локальна IP-адреса для першого встановленого (ESTABLISHED) з'єднання тепер відповідає адресі інтерфейсу SLIP каналу на багатоінтерфейсному хості sun (140.252.1.29).

Обмеження локальних IP-адрес

Ми можемо подивитися, що станеться, коли сервер не використовує символи підстановки як свої локальні IP адреси, встановлюючи натомість одну конкретну адресу локального інтерфейсу. Якщо ми вкажемо IP адресу (або ім'я хоста) нашій програмі sock, коли використовуємо її як сервер, ця IP адреса стане локальною IP адресою кінцевої точки, що слухає. Наприклад

sun % sock-s 140.252.1.29 8888

обмежує цей сервер лише для з'єднань, що прибувають із SLIP інтерфейсу (140.252.1.29). Висновок команди netstat покаже наступне:

Proto Recv-Q Send-Q Local Address Foreign Address (state)

Якщо ми приєднаємося до цього сервера через SLIP канал із хоста solaris, це спрацює.

Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp 0 0 140.252.1.29.8888 140.252.1.32.34614 ESTABLISHED
tcp 0 0 140.252.1.29.8888 *.* LISTEN

Однак, якщо ми намагатимемося приєднатися до цього сервера з хоста через Ethernet (140.252.13), запит на з'єднання не буде прийнято TCP модулем. Якщо ми подивимося за допомогою tcpdump, то побачимо, що на SYN отримано відгук RST, як показано на малюнку 18.21.

1 0.0 bsdi.1026 > sun.8888: S 3657920001:3657920001(0)
win 4096
2 0.000859 (0.0009) sun.8888 > bsdi.1026: R 0:0 (0) ack 3657920002 win 0

Рисунок 18.21 Обмеження запитів на з'єднання, що базується на локальній IP-адресі сервера.

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

Обмеження віддаленої IP-адреси

У розділі "Сервер UDP" глави 11 ми бачили, що UDP серверможе визначити віддалену IP-адресу та номер порту, на додаток до вказаних локальної IP-адреси та номера порту. Функції інтерфейсу, наведені в RFC 793, дозволяють серверу здійснювати пасивне відкриття на основі повністю описаного віддаленого сокету (у цьому випадку очікується запит на активне відкриття від конкретного клієнта) або не зазначеного віддаленого сокету (у цьому випадку очікується запит на з'єднання від будь-якого клієнта).

На жаль, більшість API не надають таких можливостей. Сервер повинен залишати віддалений сокет неконкретизованим, чекаючи на прибуття з'єднання, а потім перевіряючи IP адресу та номер порту клієнта.

На малюнку 18.22 показано три типи адрес та взаємозв'язку адрес з портами, які TCP сервер може встановити для себе. У всіх випадках lport це наперед відомий порт сервера, а localIP має бути IP адресою локального інтерфейсу. Порядок, в якому розташовані три рядки в таблиці, відповідає порядку, в якому модуль TCP намагається визначити, яка локальна кінцева точка прийме вхідний запит на з'єднання. Спочатку здійснюється спроба, що відповідає першому рядку таблиці (якщо підтримується), а потім інші специфікації (останній рядок з IP адресами, вказаними у вигляді символів підстановки) пробуються останнім.

Локальна адреса

Віддалена адреса

Опис

обмежено одним клієнтом (зазвичай не підтримується)
обмежено з'єднаннями, що прибувають з одного локального інтерфейсу: localIP
приймає всі з'єднання, надіслані на lport

Рисунок 18.22 Вказівка ​​локальної та віддаленої IP-адрес та номерів порту для TCP сервера.

Вхідна черга запитів на з'єднання

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

Реалізації Berkeley використовують такі правила.

  1. Кожна кінцева точка, що слухає, має фіксовану довжину черги з'єднань, які можуть бути прийняті TCP ("триразове рукостискання" завершено), проте ще не прийняті додатком. Будьте уважні, проводячи різницю між прийняттям з'єднання TCP і розміщенням його в чергу, і додатком, що приймає з'єднання з цієї черги.
  2. Програма вказує обмеження або межу для цієї черги, яка зазвичай називається backlog. Це обмеження має бути в діапазоні від 0 до 5. (Більшість додатків вказують максимальне значення 5.)
  3. Коли надходить запит на з'єднання (SYN сегмент), TCP переглядає поточну кількість з'єднань, поставлених у теперішній моментв чергу для цієї кінцевої точки, що слухає, при цьому він з'ясовує, чи можна прийняти з'єднання. Ми очікуємо, що значення backlog, вказане додатком, буде максимальним, тобто дозволено поставити в чергу максимальну кількість з'єднань для цієї точки, хоча це не дуже просто. На малюнку 18.23 показано взаємини між значенням backlog та реальною максимальною кількістю сполук, які можна поставити в чергу у традиційних Berkeley системах та Solaris 2.2.

значення backlog

Максимальна кількість сполук, поставлених у чергу

Традиційний BSD

Малюнок 18.23 Максимальна кількість прийнятих з'єднань для кінцевої точки, що слухає.

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

Значення для Solaris на цьому малюнку саме такі, як ми очікували. Традиційні значення для BSD (з якихось незрозумілих причин) дорівнюють значенню backlog, помноженому на 3, поділеному на 2, плюс 1.
  • Якщо в черзі для даної слухаючої кінцевої точки є місце для нового з'єднання (див. малюнок 18.23), TCP модуль підтверджує (ACK) SYN, що прийшов, і встановлює з'єднання. Додаток сервера зі слухаючою кінцевою точкою не побачить цього нового з'єднання доти, доки не буде прийнято третій сегмент з "триразового рукостискання". Також клієнт може вважати, що сервер готовий прийняти дані, коли активне відкриття клієнта завершено успішно, перш ніж програма сервера буде повідомлено про нове з'єднання. (Якщо це станеться, сервер TCP просто поставить у чергу вхідні дані.)
  • Якщо не вистачає місця для того, щоб поставити в чергу нове з'єднання, TCP просто ігнорує прийнятий SYN. У відповідь нічого не посилається (не посилається навіть сегмент RST). Якщо сервер, що слухає, не може відмовитися від прийому деяких вже прийнятих з'єднань, які заповнили собою чергу до межі, активне відкриття клієнта буде перервано по тайм-ауту.
  • Ми можемо переглянути цей сценарій з використанням програми sock. Запустимо її з новою опцією (-O), яка повідомляє про необхідність зробити паузу після створення кінцевої точки, що слухає, перед прийомом будь-якого запиту на з'єднання. Якщо потім ми запустимо кілька клієнтів протягом цієї паузи, сервер буде змушений поставити в чергу прийняті з'єднання, а те, що станеться, ми побачимо з допомогою команди tcpdump.

    bsdi % sock-s-v-q1-O30 5555

    Опція -q1 встановлює backlog слухаючої кінцевої точки значення 1, для традиційної BSD системице відповідатиме двом запитам на з'єднання (рисунок 18.23). Опція -O30 змушує програму "проспати" 30 секунд перед прийомом будь-якого з'єднання клієнта. Це дає нам 30 секунд, щоб стартувати кілька клієнтів, які заповнять чергу. Ми стартуємо чотирьох клієнтів на хості sun.

    На малюнку 18.24 показаний висновок програми tcpdump, цей висновок починається з першого SYN першого клієнта. (Ми видалили оголошення розміру вікна та оголошення MSS. Також ми виділили номери портів клієнта жирним шрифтом, коли TCP з'єднання встановлюється - "триразове рукостискання".)

    Перший запит на з'єднання від клієнта, що прийшов з порту 1090, приймається модулем TCP (сегменти 1-3). Другий запит на з'єднання від клієнта з порту 1091 також приймається модулем TCP (сегменти 4-6). Програма сервера все ще "спить" і не прийняла жодного з'єднання. Все зроблене було здійснено модулем TCP в ядрі. Також слід зазначити, що два клієнти успішно здійснили активне відкриття, тобто "триразове рукостискання" було успішно завершено.

    1 0.0 sun. 1090 > bsdi.7777: S 1617152000:1617152000(0)
    2 0.002310 (0.0023) bsdi.7777 > sun. 1090 : S 4164096001:4164096001(0)
    3 0.003098 (0.0008) сон. 1090 > bsdi.7777: . ack 1617152001
    ack 1
    4 4.291007 (4.2879) sun. 1091 > bsdi.7777: S 1617792000:1617792000(0)
    5 4.293349 (0.0023) bsdi.7777 > sun. 1091 : S 4164672001:4164672001(0)
    ack 1617792001
    6 4.294167 (0.0008) sun. 1091 > bsdi.7777: . ack 1
    7 7.131981 (2.8378) sun.1092 >
    8 10.556787 (3.4248) sun.1093 >
    9 12.695916 (2.1391) sun.1092 > bsdi.7777: S 1618176000:1618176000(0)
    10 16.195772 (3.4999) sun.1093 > bsdi.7777: S 1618688000:1618688000(0)
    11 24.695571 (8.4998) sun.1092 > bsdi.7777: S 1618176000:1618176000(0)
    12 28.195454 (3.4999) sun. 1093 > bsdi.7777: S 1618688000:1618688000(0)
    13 28.197810 (0.0024) bsdi.7777 > sun. 1093 : S 4167808001:4167808001(0)
    14 28.198639 (0.0008) sun. 1093 > bsdi.7777: . ack 1618688001
    ack 1
    15 48.694931 (20.4963) sun. 1092 > bsdi.7777: S 1618176000:1618176000(0)
    16 48.697292 (0.0024) bsdi.7777 > sun. 1092 : S 4170496001:4170496001(0)
    ack 1618176001
    17 48.698145 (0.0009) sun. 1092 > bsdi.7777: . ack 1

    Рисунок 18.24 Виведення програми tcpdump для прикладу використання backlog.

    Ми спробували стартувати третього клієнта у сегменті 7 (порт 1092) та четвертого у сегменті 8 (порт 1093). TCP ігнорувало обидва SYN, так як черга для цієї кінцевої точки, що слухає, заповнена. Обидва клієнти повторно передали свої SYN у сегментах 9, 10, 11, 12 та 15. Третя повторна передача четвертого клієнта прийнята (сегменти 12-14), тому що 30-секундна пауза сервера закінчилася, і сервер видалив два з'єднання, які були прийняті, очистивши чергу. (Причина, через яку це сталося, полягає в тому, що це з'єднання було прийнято сервером у момент часу 28.19, а не в момент часу, який більше 30; це сталося тому, що знадобилося кілька секунд, щоб стартувати першого клієнта [сегмент 1 , час старту у виведенні] після старту сервера.) Четверта повторна передача третього клієнта також прийнята (сегменти 15-17). З'єднання четвертого клієнта (порт 1093) прийнято сервером перед з'єднанням третього клієнта (порт 1092) через збіг часу між закінченням 30-секундної паузи і повторною передачею клієнта.

    Ми могли очікувати, що черга прийнятих сполук буде оброблена додатком відповідно до принципу FIFO (перший увійшов, перший вийшов). Таким чином, після того, як TCP прийняв додаток на порти 1090 і 1091, ми очікували, що програма отримає з'єднання спочатку на порт 1090, а потім з'єднання на порт 1091. Однак, у більшості реалізацій Berkeley існує помилка (bug), в результаті чого використовується порядок LIFO (останній увійшов, перший вийшов). Виробники багато разів намагалися виправити цю помилку, проте вона досі існує у таких системах, як SunOS 4.1.3.

    TCP ігнорує вхідний SYN, коли черга заповнена, і не відповідає з використанням RST через помилку. Зазвичай черга заповнена, тому що програма або операційна система зайняті, тому програма не може обробити вхідні з'єднання. Такий стан може змінитися за короткий проміжок часу. Однак, якщо TCP-сервер відповів скиданням (reset), активне відкриття клієнта буде перервано (якраз це відбудеться, якщо сервер не був стартований). Так як SYN ігнорований, TCP клієнт буде змушений повторно передати SYN пізніше, сподіваючись, що в черзі з'явиться місце для нового з'єднання.

    Тут необхідно обговорити ще одну дуже важливу деталь, яка є практично у всіх реалізаціях TCP/IP. Вона у тому, що TCP приймає вхідний запит на з'єднання (SYN) у разі, якщо у черзі є місце. При цьому програма не може подивитися, від кого надійшов запит (IP адреса джерела та номер порту джерела). Це не потрібно TCP, це лише загальна техніка, що використовується в реалізаціях. Якщо API, такий як TLI (розділ "Інтерфейси прикладного програмування" глави 1), повідомляє додаток про прибуття запиту на з'єднання і дозволяє додатку вибрати, прийняти це з'єднання чи ні, то при використанні TCP виходить так, що коли додатку повідомляється, що з'єднання тільки що прибуло, насправді TCP вже завершив "триразове рукостискання"! В інших транспортних рівнях існує можливість розмежувати прибуле і прийняте з'єднання (OSI транспортний рівень), проте TCP такої можливості не надає.

    Solaris 2.2 надає опцію, яка не дозволяє TCP приймати вхідний запит на з'єднання доти, доки йому це не дозволить програму (tcp_eager_listeners у розділі "Solaris 2.2" програми E).

    Ця поведінка також означає, що TCP сервер не може зробити так що активне відкриття клієнта буде перервано. Коли з'єднання від нового клієнта потрапляє до програми сервера, "тристороннє рукостискання" TCP вже закінчено і активне відкриття клієнта завершено успішно. Якщо сервер потім дивиться на IP-адресу клієнта і номер порту і вирішує, що він не хоче обслуговувати цього клієнта, всі сервери можуть просто закрити з'єднання (при цьому буде надіслано FIN) або скинути з'єднання (буде послано RST). У будь-якому разі клієнт вважатиме, що з сервером все нормально, оскільки завершилося активне відкриття, і, цілком можливо, вже надіслав серверу будь-який запит.

    Короткі висновки

    Перед тим, як два процеси зможуть обмінюватися даними з використанням TCP, вони повинні встановити з'єднання між собою. Коли роботу між ними закінчено, з'єднання має бути розірвано. У цьому розділі детально розглянуто, як встановлюється з'єднання з використанням "триразового рукостискання" і як воно розривається з використанням чотирьох сегментів.

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

    Щоб зрозуміти функціонування TCP, необхідно розглянути фундаментальну діаграму зміни станів TCP. Ми розглянули пункти, як встановлюється та розривається з'єднання, і які при цьому відбуваються зміни в стані. Також ми розглянули, як сервери TCP здійснюють встановлення з'єднань TCP.

    TCP з'єднання унікально ідентифікуються 4 параметрами: локальною IP адресою, локальним номером порту, віддаленою IP адресою та віддаленим номером порту. Якщо з'єднання розривається, одна сторона все одно повинна пам'ятати про це з'єднання, в цьому випадку ми говоримо, що працює режим TIME_WAIT. Правило говорить, що ця сторона може здійснити активне відкриття, увійшовши в цей режим, після того як минув подвоєний час MSL, прийнятий для цієї реалізації.

    Вправи

    У розділі ми сказали, що вихідний номер послідовності (ISN) зазвичай встановлюється в 1 і збільшується на 64000 кожні півсекунди і щоразу, коли здійснюється активне відкриття. Це означає, що молодші три цифри в ISN завжди будуть 001. Однак на малюнку 18.3 ці молодші три цифри для кожного напряму дорівнюють 521. Як це сталося?
  • На малюнку 18.15 ми надрукували 12 символів, але бачили, що TCP надіслав 13 байт. На малюнку 18.16 ми надрукували 8 символів, проте TCP надіслав 10 байт. Чому в першому випадку було додано 1 байт, а в другому 2 байти?
  • У чому полягає відмінність між напіввідкритим з'єднанням та напівзакритим з'єднанням?
  • Якщо ми стартуємо програму sock як сервер, а потім перервемо її роботу (при цьому до неї не було підключено жодного клієнта), ми можемо негайно перестартувати сервер. Це означає, що він не перебуватиме в стані очікування 2MSL. Поясніть це у термінах діаграми зміни станів.
  • У розділі ми показали, що клієнт не може повторно використовувати той самий локальний номер порту, поки порт є частиною з'єднання в стані очікування 2MSL. Однак, якщо ми запустимо програму sock двічі поспіль як клієнт, приєднуючись до сервера часу, ми можемо використовувати той самий локальний номер порту. Крім того, ми можемо створити нове з'єднання, яке буде в стані очікування 2MSL. Як це відбувається?

  • sun % sock -bsdi daytime

    Wed Jul 7 07:54:51 1993
    connection closed by peer

    Sun % sock-v-b1163 bsdi daytimeповторне використання того ж номера локального порту
    connected on 140.252.13.33.1163 to 140.252.13.35.13
    Wed Jul 7 07:55:01 1993
    connection closed by peer

  • В кінці розділу , коли ми описували стан FIN_WAIT_2, ми вказали, що більшість реалізацій переводить з'єднання з цього стану в стан CLOSED, якщо програма здійснила повне закриття (не наполовину закритий) приблизно через 11 хвилин. Якщо інша сторона (в стані CLOSE_WAIT) чекає 12 хвилин перед закриттям (відправлення свого FIN), що його TCP отримає у відповідь на FIN?
  • Яка сторона в телефонній розмовіздійснює активне відкриття, а яка здійснює пасивне відкриття? Чи можливе одночасне відкриття? Чи можливе одночасне закриття?
  • На малюнку 18.6 ми не бачили запит ARP або ARP відгук. Однак апаратна адреса хоста svr4 має бути в ARP кеші bsdi. Що зміниться на цьому малюнку, якщо цього пункту в ARP кеші немає?
  • Поясніть наступний висновоккоманди tcpdump. Порівняйте його з малюнком 18.13.

  • 1 0.0 solaris.32990 > bsdi.discard: S 40140288:40140288 (0)
    win 8760
    2 0.003295 (0.0033) bsdi.discard > solaris.32990: S 4208081409:4208081409 (0)
    ack 40140289 win 4096

    3 0.419991 (0.4167) solaris.32990 > bsdi.discard: P 1:257 (256) ack 1 win 9216
    4 0.449852 (0.0299) solaris.32990 > bsdi.discard: F 257:257 (0) ack 1 win 9216
    5 0.451965 (0.0021) bsdi.discard > solaris.32990: . ack 258 win 3840
    6 0.464569 (0.0126) bsdi.discard > solaris.32990: F 1:1 (0) ack 258 win 4096
    7 0.720031 (0.2555) solaris.32990 > bsdi.discard: . ack 2 win 9216
  • Чому серверу на малюнку 18.4 не скомбінувати ACK на FIN клієнта зі своїм власним FIN, зменшивши тим самим кількість сегментів до трьох?
  • На малюнку 18.16 чому номер послідовності RST дорівнює 26368002?
  • ми показали, що вхідні сегменти TCP демультиплексуються на основі номера порту призначення TCP. Чи правильно це?

    Хоча є і реалізації TCP у контексті програми.

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

    Заголовок сегмента TCP

    Заголовок сегмента TCP
    Біт 0 - 3 4 - 9 10 - 15 16 - 31
    0 Порт джерела Порт призначення
    32 Номер послідовності
    64 Номер підтвердження
    96 Зміщення даних Зарезервовано Прапори Розмір Вікна
    128 Контрольна сума Вказівник важливості
    160 Опції (необов'язковий, але використовується практично завжди)
    160/192+
    Дані

    Порт джерела

    Номер послідовності

    Номер послідовності виконує два завдання:

    1. Якщо встановлено прапорець SYN, це початкове значення номера послідовності - ISN (Initial Sequence Number), і перший байт даних, які будуть передані в наступному пакеті, матиме номер послідовності, що дорівнює ISN + 1.
    2. В іншому випадку, якщо SYN не встановлений, перший байт даних, що передається в цьому пакеті, має номер послідовності.

    Оскільки потік TCP у випадку може бути довше, ніж кількість різних станів цього поля, всі операції з номером послідовності повинні виконуватися по модулю 2^32. Це накладає практичне обмеження використання TCP. Якщо швидкість передачі комунікаційної системи така, щоб протягом MSL (максимального часу життя сегмента) відбулося переповнення номера послідовності, то в мережі може з'явитися два сегменти з однаковим номером, що стосуються різним частинампотоку і приймач отримає некоректні дані.

    Номер підтвердження

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

    Зміщення даних

    Це поле визначає розмір заголовка TCP в 4-байтних (4-октетних) словах. Мінімальний розмірскладає 5 слів, а максимальний - 15, що становить 20 та 60 байт відповідно. Усунення вважається від початку заголовка TCP.

    Зарезервовано

    Зарезервовано (6 біт) для майбутнього використання та має встановлюватися в нуль. З них два (5-й та 6-й) вже визначено:

    • CWR(Congestion Window Reduced) - Поле "Вікно перевантаження зменшено" - прапор встановлений відправником, щоб вказати, що отримано пакет із встановленим прапором ECE (RFC 3168)
    • ECE(ECN-Echo) - Поле «Ехо ECN» - вказує, що даний вузол здатний на ECN (явне повідомлення перевантаження) та для вказівки відправнику про навантаження в мережі (RFC 3168)

    Прапори (керуючі біти)

    Це поле містить 6 бітових прапорів:

    • URG- Поле «Покажчик важливості»задіяно (англ. Urgent pointer field is significant )
    • ACK- Поле «Номер підтвердження»задіяно (англ. Acknowledgement field is significant )
    • PSH- (Англ. Push function) інструктує одержувача проштовхнути дані, що накопичилися в приймальному буфері, додаток користувача
    • RST- Обірвати з'єднання, скинути буфер (очищення буфера) (англ. Reset the connection)
    • SYN- синхронізація номерів послідовності (англ. Synchronize sequence numbers)
    • FIN(англ. final, біт) - прапор, встановлений, вказує на завершення з'єднання (англ. FIN bit used for connection termination ).

    Вікно

    У цьому полі міститься число, що визначає в байтах розмір даних, які відправник готовий прийняти.

    Псевдозаголовок

    TCP-заголовок не містить інформації про адресу відправника та одержувача, тому навіть при збігу порту одержувача не можна точно сказати, що повідомлення прийшло в потрібне місце. Оскільки призначенням протоколу TCP є надійна доставка повідомлень, цей момент має важливе значення. Це завдання можна було вирішити у різний спосіб. Найочевидніший - додати інформацію про адресу призначення в заголовок TCP, проте це, по-перше, призводить до дублювання інформації, що знижує частку корисної інформації, що переноситься TCP-сегментом, а по-друге, порушує принцип інкапсуляції моделі OSI. Тому розробники протоколу пішли іншим шляхом та використовували додатковий псевдозаголовок:

    TCP-псевдозаголовок IPv4

    TCP-псевдозаголовок IPv6

    • Протокол (Protocol)/Протокол верхнього рівня(Next header) - містить значення 6 (000000110 в двійковому вигляді, 0x6 - у шістнадцятковому) - ідентифікатор TCP-протоколу.
    • Довжина TCP-сегмента (TCP length) - містить у собі довжину TCP-сегмента в байтах (TCP-заголовок + дані; довжина псевдозаголовка не враховується).

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

    Контрольна сума

    Поле контрольної суми - це 16-бітове доповнення до всіх 16-бітних слів заголовка (включаючи псевдозаголовок) і даних. Якщо сегмент, яким обчислюється контрольна сума, має довжину не кратну 16-ти бітам, то довжина сегмента збільшується до кратної 16-ти, з допомогою доповнення щодо нього справа нульових бітів заповнення. Біти заповнення (0) не передаються в повідомленні та служать лише для розрахунку контрольної суми. При розрахунку контрольної суми значення поля контрольної суми приймається рівним 0.

    Вказівник важливості

    16-бітове значення позитивного усунення від порядкового номера в даному сегменті. Це поле вказує порядковий номер октету, яким закінчуються важливі дані. Поле береться до уваги лише для пакетів із встановленим прапором URG.

    Опції

    Можуть застосовуватись у деяких випадках для розширення протоколу. Іноді використовуються для тестування. на НаразіВ опції практично завжди включають 2 байти NOP (в даному випадку 0x01) і 10 байт, що задають timestamps . Обчислити довжину поля опції можна значення поля зміщення.

    Механізм дії протоколу

    На відміну від традиційної альтернативи- UDP, який може відразу розпочати передачу пакетів, TCP встановлює з'єднання, які мають бути створені перед передачею даних. TCP з'єднання можна розділити на 3 стадії:

    • Встановлення з'єднання
    • Передача даних
    • Завершення з'єднання

    Стан сеансу TCP

    Стан сеансу TCP
    CLOSED Початковий стан вузла. Фактично фіктивне
    LISTEN Сервер чекає на запити встановлення з'єднання від клієнта
    SYN-SENT Клієнт надіслав запит серверу на встановлення з'єднання та чекає відповіді
    SYN-RECEIVED Сервер отримав запит на з'єднання, відправив запит у відповідь і чекає підтвердження
    ESTABLISHED З'єднання встановлено, йде передача даних
    FIN-WAIT-1 Одна зі сторін (назвемо її вузол-1) завершує з'єднання, відправивши сегмент із прапором FIN
    CLOSE-WAIT Інша сторона (вузол-2) перетворюється на цей стан, відправивши, своєю чергою сегмент ACK і продовжує односторонню передачу
    FIN-WAIT-2 Вузол-1 отримує ACK, продовжує читання і чекає на отримання сегмента з прапором FIN
    LAST-ACK Вузол-2 закінчує передачу та відправляє сегмент із прапором FIN.
    TIME-WAIT Вузол-1 отримав сегмент із прапором FIN, відправив сегмент із прапором ACK і чекає 2*MSL секунд, перед остаточним закриттям з'єднання
    CLOSING Обидві сторони ініціювали закриття з'єднання одночасно: після відправки сегмента з прапором FIN вузол-1 також отримує сегмент FIN, відправляє ACK і перебуває в очікуванні сегмента ACK (підтвердження на запит про роз'єднання)

    Встановлення з'єднання

    Процес початку сеансу TCP - що позначається як "рукостискання" (handshake), складається з 3 кроків.

    1. Клієнт, який має намір встановити з'єднання, надсилає серверу сегмент із номером послідовності та прапором SYN.

    • Сервер отримує сегмент, запам'ятовує номер послідовності та намагається створити сокет (буфери та керуючі структури пам'яті) для обслуговування нового клієнта.
      • У разі успіху сервер посилає клієнту сегмент із номером послідовності та прапорами SYN та ACK, і переходить у стан SYN-RECEIVED.
      • У разі невдачі сервер посилає клієнту сегмент із прапором RST.

    2. Якщо клієнт отримує сегмент з прапором SYN, він запам'ятовує номер послідовності і посилає сегмент з прапором ACK.

    • Якщо він одночасно отримує і прапор ACK (що зазвичай і відбувається), він переходить у стан ESTABLISHED.
    • Якщо клієнт отримує сегмент з прапором RST, він припиняє спроби з'єднатися.
    • Якщо клієнт не отримує відповіді протягом 10 секунд, він повторює процес з'єднання заново.

    3. Якщо сервер може SYN-RECEIVED отримує сегмент з прапором ACK, він перетворюється на стан ESTABLISHED.

    • В іншому випадку після тайм-ауту він закриває сокет і переходить у стан CLOSED.

    Процес називається "трьохетапним узгодженням" ("three way handshake"), так як незважаючи на те що можливий процес встановлення з'єднання з використанням 4 сегментів (SYN у бік сервера, ACK у бік клієнта, SYN у бік клієнта, ACK у бік сервера), на практиці для економії часу використовується 3 сегменти.

    Приклад базового 3-етапного узгодження:

    TCP A TCP B 1. CLOSED LISTEN 2. SYN-SENT --> --> SYN-RECEIVED 3. ESTABLISHED<-- <-- SYN-RECEIVED 4. ESTABLISHED --> --> ESTABLISHED 5. ESTABLISHED<-- <-- ESTABLISHED

    У рядку 2 TCP A починає передачу сегмента SYN, що говорить про використання номерів послідовності, починаючи зі 100. У рядку 3 TCP B передає SYN і підтвердження для прийнятого SYN на адресу TCP A. Потрібно зазначити, що поле підтвердження показує очікування TCP B прийому номера послідовності 101, що підтверджує SYN із номером 100.

    У рядку 4 TCP A відповідає порожнім сегментом з підтвердженням ACK сегмента SYN від TCP B; у рядку 5 TCP B передає деякі дані. Зазначимо, що номер послідовності сегмента у рядку 5 збігається з номером у рядку 4, оскільки ACK не займає простору номерів послідовності (якщо це зробити, доведеться підтверджувати підтвердження - ACK для ACK!).

    Передача даних

    При обміні даними приймач використовує номер послідовності, що міститься в сегментах, що отримуються, для відновлення їх вихідного порядку. Приймач повідомляє передавальну сторону номер послідовності байт, до якої він успішно отримав дані, включаючи його в полі «номер підтвердження». Всі дані, що належать до проміжку підтверджених послідовностей, ігноруються. Якщо отриманий сегмент містить номер послідовності більший, ніж очікуваний, дані з сегмента буферизуються, але номер підтвердженої послідовності не змінюється. Якщо згодом буде прийнятий сегмент, що відноситься до очікуваного номера послідовності, порядок даних буде автоматично відновлено виходячи з номерів послідовностей в сегментах.

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

    У деяких випадках передавальна програма може явно зажадати проштовхнути дані до деякої послідовності приймаючому додатку, не буферизуючи їх. Для цього використовується прапор PSH. Якщо в отриманому сегменті виявляється прапор PSH, то реалізація TCP віддає всі буферизовані на даний момент дані додатку, що приймає. "Проштовхування" використовується, наприклад, в інтерактивних програмах. У мережевих терміналах немає сенсу очікувати на введення користувача після того, як він закінчив набирати команду. Тому останній сегмент, що містить команду, повинен містити прапор PSH, щоб додаток на стороні, що приймає, змогло почати її виконання.

    Завершення з'єднання

    Завершення з'єднання можна розглянути у три етапи:

    1. Надсилання серверу від клієнта прапорів FIN та ACK на завершення з'єднання.
    2. Сервер посилає клієнту прапори відповіді ACK, FIN, що з'єднання закрите.
    3. Після отримання цих прапорів клієнт закриває з'єднання і підтверджує відправляє серверу ACK , що з'єднання закрито.

    Відомі проблеми

    Максимальний розмір сегмента

    TCP вимагає явної вказівки максимального розміру сегмента (MSS) у разі, якщо віртуальне з'єднання здійснюється через сегмент мережі, де максимальний розмір блоку (MTU) менший за стандартний MTU Ethernet (1500 байт).

    У протоколах тунелювання, таких як GRE , IPIP, а також PPPoE MTU тунелю менше стандартного, тому сегмент TCP максимального розміру має довжину пакета більше, ніж MTU. Оскільки фрагментація в переважній більшості випадків заборонена, такі пакети відкидаються.

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

    Для вирішення цієї проблеми на маршрутизаторах застосовуються правила Firewall-а, що додають параметр MSS у всі пакети, що ініціюють з'єднання, щоб відправник використовував сегменти допустимого розміру.

    MSS також може керуватися параметрами операційної системи.

    Виявлення помилок під час передачі даних

    Хоча протокол здійснює перевірку контрольної суми по кожному сегменту, алгоритм вважається слабким . Так, у 2008 році не виявлена ​​мережевими засобами помилка в передачі одного біта, призвела до зупинки серверів системи Amazon Web Services.

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

    Атаки на протокол

    Основна стаття: Атаки на TCP

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

    Реалізація

    Звільнення від розрахунку контрольної суми

    Багато реалізації стека TCP/IP надають можливості використання апаратної підтримки для автоматичного розрахунку контрольної суми в мережевому адаптері до передачі до мережі або після прийому з мережі для верифікації. Це може звільняти операційну систему використання цінних тактів процесора при обчисленні контрольної суми.

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

    Див. також

    Посилання

    • RFC 793 - Transmission Control Protocol

    Література

    • Террі Оглтрі.Модернізація та ремонт мереж = Upgrading and Repairing Networks. - 4-те вид. – М.: «Вільямс», 2005. – С. 1328. – ISBN 0-7897-2817-6
    • Дуглас Камер.Мережі TCP/IP, том 1. Принципи, протоколи та структура = Internetworking with TCP/IP, Vol. 1: Principles, Protocols and Architecture. – М.: «Вільямс», 2003. – С. 880. – ISBN 0-13-018380-6
    • Андрій Робачевський, Сергій Немнюгін, Ольга Стесик.Операційна система UNIX. - 2-ге вид. - "БХВ-Петербург", 2007. - С. 656. -