Зачем?

Вообще, да, транспортный уровень (кстати, это четвертый уровень модели OSI, о которой я наверняка когда-то напишу) — это не тот уровень, на котором работает наш любимый HTTP (о котором подробнее здесь). Точнее, вообще-то, он работает поверх TCP — и именно поэтому я решил немного разобрать и его тоже. Не то чтобы это напрямую важно для Node.js-разработчика, но мы здесь в том числе про эрудицию, поэтому давайте вкуривать.

TCP

Расшифровывается TCP как Transmission Control Protocol (протокол управления передачей) — и используется почти везде в интернете (ну, там, где не используется UDP, о котором чуть позже). Если сильно вкратце, то TCP устанавливает соединение (и это важное его отличие от UDP, которому это не нужно) и обменивается по этому соединению пакетами (которые почему-то называются сегментами).

Собственно, это самое установление соединения несколько замедляет процесс передачи данных, но дает неоспоримое преимущество перед тем же UDP — TCP гарантирует доставку данных. Давайте попробуем разобрать процесс установки соединения и передачи данных по TCP.

TCP: состояния соединения

  • CLOSED: начальное состояние соединения
  • LISTEN: сервер ожидает запросов
  • SYN-SENT: клиент отправил серверу запрос на создание соединения
  • SYN-RECEIVED: сервер получил запрос на создание соединения и отправил ответный запрос клиенту
  • ESTABLISHED: соединение установлено
  • FIN-WAIT-1: какая-то из сторон отправила запрос на завершение соединения
  • CLOSE-WAIT: другая сторона получила этот запрос, отправила в ответ пакет с флагом ACK и продолжает передачу данных
  • FIN-WAIT-2: первая сторона получила ACK и ждет пакета с флагом FIN, чтобы завершить соединение
  • LAST-ACK: вторая сторона заканчивает передачу данных и отправляет пакет FIN
  • TIME-WAIT: первая сторона получила пакет FIN, отправила пакет ACK и ждет закрытия соединения
  • CLOSING: обе стороны закрыли соединение

TCP: установка соединения

Установка соединения по TCP (handshake) состоит из трех шагов:

  1. клиент, желающий установить соединение с сервером в состоянии LISTEN, посылает ему сегмент с номером последовательности (такая штука, которая позволяет обеим сторонам считать количество переданных / полученных пакетов) и флагом SYN. Соединение переходит в состояние SYN-SENT
  2. сервер получает пакет, в случае успеха запоминает номер последовательности и посылает клиенту сегмент с номером последовательности и флагами SYN и ACK, а соединение переходит в состояние SYN-RECEIVED. В случае неуспеха сервер просто посылает пакет с флагом RST
  3. если клиент получает пакет SYN, он запоминает номер последовательности и посылает пакет с флагом ACK. Если клиент получает еще и ACK, то он переходит в состояние ESTABLISHED. Если же он получает пакет с флагом RST, то он прекращает попытки установить соединение. А если клиент не получает ничего в течение 10 секунд, он повторяет все заново
  4. если сервер в состоянии SYN-RECEIVED получает от клиента ACK, он переходит в состояние ESTABLISHED. Иначе он по таймауту перейдет в состояние CLOSED

(извините за всю эту сложность. Я описал все именно так только потому, чтобы было понятно, насколько времязатратно установление соединения по TCP. Это, к примеру, поможет нам понять преимущества HTTP/2 — подробности в статье об HTTP).

Что хочется добавить: TCP используется там, где гарантия доставки пакетов и их порядок гораздо важнее скорости. Для нас, как для веб-разработчиков, важнее всего, что его использует протокол HTTP.

UDP

UDP (User Datagram Protocol, протокол пользовательских диаграмм) — штука ощутимо более простая уже потому, что не требует установки соединения. Из этого следует, что он ощутимо быстрее. Из этого же следует, что он не гарантирует доставки пакетов и их порядка, в отличие от TCP.

UDP удобно использовать там, где скорость важнее, чем гарантия доставки — передача видео / аудио, разного рода игровых данных и прочего такого. UDP — несравненно более простая и топорная штука, чем TCP, но свое применение, конечно, находит. Нам, как веб-разработчикам, может быть интересно, что по UDP часто работает WebRTC, штука для передачи потоковых данных между браузерами.

Выводы

Если коротко: TCP медленнее за счет установки соединения, но гарантирует порядок доставки пакетов и саму их доставку. UDP тупее, но быстрее — он просто пуляет пакетами, куда ему скажешь.

Знать такие вещи нам, веб-разработчикам, надо в первую очередь потому, что поверх этих протоколов работают штуки, с которыми работаем мы (HTTP, WebRTC и так далее). Ну, и да, мы здесь еще и про кругозор, а не только про Node.js.