Урок 4. Протоколы Транспортного уровня стека TCP/IP

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

Кроме того, он не исправляет ошибки в принятых данных. Если будут обнаружены ошибки, то данные сегменты будут просто уничтожены и без запроса повторной передачи. 

Для чего тогда такой протокол нужен? 

Он очень полезен там, где передаваемые данные очень критичны к задержкам. Например, при передаче видео и голоса.  Там недопустимы задержки, но можно пожертвовать несколькими пакетами в случае обнаружения ошибок - человеческие ухо и глаз не способны заметить потерю нескольких пакетов (если, конечно, число таких пакетов не слишком велико). 

Однако для передачи чувствительных данных он совсем не годится, например, при передаче файлов - в данном случае задержки допустимы, но файл должен быть доставлен целостным. 

Протокол добавляет следующий заголовок к передаваемым данным:

Заголовок протокола UDP
Рис. 1. Заголовок протокола UDP

Порт отправителя - идентифицирует приложение прикладного уровня, которое хочет общаться с таким же или другим приложением по сети. Например, Skype использует порт 80. Хотя может использовать и другие порты в зависимости от настроек. То есть, если Алиса пишет сообщение Кате по Skype, то компьютер Кати, приняв сообщение, сможет по номеру порта отправителя определить какое приложение отправило данное сообщение. 

Порт получателя - идентифицирует приложение прикладного уровня, которое принимает сообщения от удаленных узлов. Иными словами, приложение “слушает” сеть на этом порту. Например, тот же Skype может принимать сообщение на порту 80. То есть, если Алиса отправит сообщение Кате на порт 80, то компьютер Кати его примет (при условии, что Skype будет в это время работать). Однако если, Алиса отправит на порт 100, а Катя слушает на порту 80, то компьютер Кати просто отбросит принятое сообщение. 

А сколько всего может быть таких портов? 

Всего насчитывается 65535 портов. Из них с 0 по 1023 зарезервированы под стандартные приложения, такие как FTP, SMTP, SNMP и другие. Остальные порты с 1024 и по 65535 могут быть использованы для любых других приложений. Эти порты еще называют динамическими, потому что у них нет жесткой привязки к определенному приложению и могут меняться от сеанса к сеансу. 

Длина дейтаграммы - определяет длину всего сегмента, включая и сам заголовок. 

Контрольная сумма - используется для проверки на наличие ошибок. 

Как работает проверка? 

Способ довольно примитивный. Передающий компьютер вычисляет контрольную сумму всего сегмента по специальному алгоритму и помещает это значение в поле Checksum. Затем принимающий компьютер вычисляет контрольную сумму данного сегмента и сравнивает с суммой в поле Checksum. Если значения совпадают, то сегмент принимается, в противном случае уничтожается. 

И что произойдет дальше? 

Ничего, UDP не заботится о дальнейшей судьбе потерянных данных. 

TCP (Transmission Control Protocol) - Протокол Управления Передачей. Надежный протокол передачи данных. С помощью него устанавливается и поддерживается связь с удаленными узлами, управляется скорость передачи данных, контролируются ошибки при передаче данных. 

Вот как выглядит заголовок сегмента TCP:

Заголовок протокола TCP
Рис. 2. Заголовок протокола TCP

С некоторыми полями мы уже знакомы. Опишем новые поля. 

Порядковый номер  - каждый байт в отправленном сегменте нумеруется для того, чтобы на приеме правильно собрать все сегменты в единый поток. Кроме того, с помощью номера контролируется весь поток данных и исправляются поврежденные сегменты. 

Номер подтверждения - чтобы убедиться, что все переданные сегменты достигли адресата используются номера подтверждения. Например, узел А отправил сегмент с порядковым номером 45 узлу В. Когда узел В примет сегмент с номером 45, то отправит узлу А пустой сегмент с подтверждающим номером 46. Узел А будет знать, что все в порядке и отправит следующий сегмент под номером 46. 

Флаги - специальные знаки-сигналы, указывающие на состояние сессии. Например, запрос на установление соединения или запрос на разрыв соединения.

Размер окна - определяет количество байт для отправки за один раз. Принимающий узел отправит подтверждение только для последнего байта в сегменте. Таким образом не нужно отправлять подтверждение за каждый байт, экономя тем самым время и канал связи. Например, если размер окна равен 500, то передающий узел сразу же отправит 500 байт данных в сегменте. Принимающий узел, получив все 500 байт, отправит лишь одно подтверждение. Размер окна может меняться в течении всего сеанса связи для регулирования скорости передачи. 

А кто устанавливает размер окна? 

Оба участника соединения. Например, принимающий узел сообщает передающему узлу размер окна исходя из того, как быстро принимающий узел справляется с поступающими данными. Если он не успевает обработать данные, то уменьшает размер и окна и передающий узел обязан уменьшить объем передаваемых данных. Чтобы лучше понять назначение всех этих полей рассмотрим принцип работы протокола на примере установления соединения.

Установление соединения (Трехэтапное квитирование)

Процесс установления связи осуществляется в 3 этапа.  

Этап 1

Когда сторона А хочет установить связь со стороной В, то сторона А отправляет запрос с установленным флагом SYN. После этого узел А переходит в состояние SYN SENT. Узел В остается в состоянии LISTEN:

Первый этап установления TCP соединения
Рис. 3. Первый этап установления TCP соединения

Вот какие данные устанавливаются в заголовке TCP (для упрощения восприятия некоторые данные опущены):

Заголовок TCP при первом этапе
Рис. 4. Заголовок TCP при первом этапе

Вот как выглядит запрос в сетевом анализаторе:

Отображение первого этапа соединения в Wireshark
Рис. 5. Отображение первого этапа соединения в Wireshark

Генерируется порядковый номер ISNa = 1 и формируется запрос на установление соединения. Если по истечении таймаута со стороны В не поступает никакого ответа, то узел А снова отправит запрос узлу В.

Этап 2

Когда сторона В принимает запрос SYN, то тоже генерируется порядковый номер ISNb = 200 (в реальности номер может принимать другие значения) для своего сегмента. Для формирования ответа стороне А, узел В устанавливает 2 флага: SYN и ACK. Причем в качестве номера подтверждения берется порядковый номер сегмента стороны А и увеличивается на 1, то есть 1 + 1. Это означает, что запрос успешно принят и ожидается следующий сегмент с номером 2. После того, как сегмент отправлен, узел В переходит в состояние SYN-RECEIVED, узел А остается в состоянии SYN SENT:

Второй этап TCP соединения
Рис. 6. Второй этап TCP соединения

Вот какие данные устанавливаются в заголовке TCP:

TCP заголовок при втором этапе соединения
Рис. 7. TCP заголовок при втором этапе соединения

Вот как выглядит запрос в сетевом анализаторе:

Отображение второго этапа соединения в Wireshark
Рис. 8. Отображение второго этапа соединения в Wireshark

Если по истечении таймаута от узла А не поступит подтверждения, то узел В снова отправит свой запрос.

Этап 3

После того, как узел А примет сразу 2 флага SYN и ACK, причем ACK будет на 1 больше ISN узла А, то сторона А сразу отправит второй сегмент узлу В. ISN будет увеличен на 1. Флаг будет установлен на ACK со значением ISNb + 1, то есть 200 + 1:

Третий этап соединения
Рис. 9. Третий этап соединения
TCP заголовок при третьем этапе соединения
Рис. 10. TCP заголовок при третьем этапе соединения
Отображение третьего этапа соединения в Wireshark
Рис. 11. Отображение третьего этапа соединения в Wireshark

После этого соединение считается успешно установленным, то есть помечается как ESTABLISHED.

Отказ в установлении соединения 

Если сторона В по каким-то причинам не может установить соединение со стороной А, то генерируется ответ с флагом RST, которой информирует о прекращении попыток установления связи:

Отказ в установлении TCP соединения
Рис. 12. Отказ в установлении TCP соединения
TCP заголовок при отказе в соединении
Рис. 13. TCP заголовок при отказе в соединении

 

Отображение отказа в соединении в Wireshark
Рис. 14. Отображение отказа в соединении в Wireshark
Завершение связи 

Когда одна из сторон желает завершить сеанс связи, то формирует запрос FIN и переходит в состояние FIN_WAIT 1:

Первый этап завершения TCP соединения
Рис. 15. Первый этап завершения TCP соединения

Сторона В подтверждает запрос отправкой ACK и переходит в состояние CLOSE_WAIT. Сразу же вслед посылается запрос FIN. После этого узел В переходит в состояние LAST_ACK:

Второй этап завершения TCP соединения
Рис. 16. Второй этап завершения TCP соединения

Сторона А подтверждает отправкой ACK и переходит в состояние CLOSED. Когда узел В примет ACK, то также перейдет в состояние CLOSED. На этом сеанс связи завершен:

Третий этап завершения TCP соединения
Рис. 17. Третий этап завершения TCP соединения
Контроль над искаженными и потерянными данными 

Концепция TCP такова, что передатчик ожидает от приемника получение подтверждения успешного принятия байта. Пока передатчик не убедится, что данные успешно доставлены получателю он не будет передавать следующую порцию данных. Однако подтверждать каждый переданный байт слишком дорогое удовольствие - растет нагрузка на сеть, значительно замедляется работа протокола.  

Поэтому передатчик отправляет сразу несколько сегментов и ждет подтверждения от приемника. Приемнику в свою очередь достаточно отправить одно подтверждение на последний полученный сегмент.

Передатчик поймет, что все отправленные сегменты успешно получены и сразу же отправит очередной набор сегментов:

Подтверждение получения сегментов
Рис. 18. Подтверждение получения сегментов

Для реализации данного механизма и используются порядковые и подтверждающие номера. Каждый сегмент нумеруется первым байтом полезной нагрузки. Затем приемник посылает подтверждающий сегмент, где указывает номер первого байта следующего сегмента. Например, первый сегмент имеет 100 байт полезной нагрузки (заголовок не учитывается), второй сегмент - 200 байт. Первому байту первого сегмента присваивается номер 1, у первого байта второго сегмента номер соответственно равен 101 (100 + 1) и так далее:

Нумерация сегментов
Рис. 19. Нумерация сегментов

 Теперь посмотрим как будет проходить передача сегментов:

Передача 3-х сегментов и одно подтверждение с указанием всех номеров
Рис. 20. Передача 3-х сегментов и одно подтверждение с указанием всех номеров

Вот как это выглядит в сетевом анализаторе:

Отображение передачи данных в сетевом анализаторе
Рис. 21. Отображение передачи данных в сетевом анализаторе

Если сложить ISN = 2155299270 первого сегмента с длиной данных Len = 711, то получится ISN = 2155299981 второго сегмента. Таким способом приемник формирует ACK SN для 3-го сегмента.

С этим разобрались. Но что произойдет, если данные потеряны или искажены в процессе передачи?

Представим, что сегмент дошел до получателя, однако содержит ошибки. Это проверяется  с помощью контрольной суммы. Тогда приемник сбросит искаженный сегмент и отправит подтверждение только за предпоследний сегмент. Передатчик поймет, что первые 2 сегмента получены без ошибок и снова отправит 3-й сегмент:

 

Повторная отправка сегментов при возникновении ошибки
Рис. 22. Третий сегмент оказался искажен при отправке

Теперь посмотрим, что произойдет, если один сегмент не дойдет до получателя. В данном случае приемник вышлет подтверждение только за принятые сегменты. А о 3-ем сегменте он вообще ничего не знает, поэтому ничего не отправит.

Передатчик будет ждать определенное время и не дождавшись подтверждения за 3-й сегмент вышлет его снова:

Повторная передача сегмента
Рис. 23. Повторная передача сегмента

Вот так и достигается контроль над ошибками данных.

Контроль за передачей данными (Метод скользящего окна) 

Протокол TCP является дуплексным, то есть может одновременно работать на прием и передачу. Для этого на приеме и передаче устанавливаются буферы.  

Передающий буфер содержит переданные, но еще не подтвержденные байты, а также байты готовые для передачи. Приемный буфер содержит принятые байты для последующей обработки. 

Но для чего нужны буферы, разве не может приемник сразу же обработать поступивший сегмент? 

Буферы необходимы для постановки в очередь принятые и передаваемые данные, так как производительность приёмной и передающей систем, а также самой сети разные, то велика вероятность, что система не сможет на “лету” обработать большой объем данных. Мы знаем, что передатчик может сразу отправить несколько сегментов данных, не дожидаясь подтверждения на каждый сегмент.

Но что делать, если передатчик передает данные с большой скоростью, а буфер приемника не успевает их всех вместить? 

Тогда приемник просто сбросит новые поступающие данные и отправит подтверждения только на полученные и обработанные сегменты. Передатчику придется повторно отправлять данные, пока не получит подтверждения успешного получения.  

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

И как работает данный механизм? 

В TCP заголовке имеется поле “Размер окна (Window size)”, которое указывает на то, сколько байт приемник способен принять. Иными словами это говорит о доступности буфера и наличии в нем свободного пространства для поступающих данных. 

После установления соединения приемник сообщает передатчику размер окна. Например, приемник сообщил, что окно равно 5 байтам. Передатчик передаст 5 байт информации и ждет подтверждения:

Отправка первых 5 байтов в окне
Рис. 24. Отправка первых 5 байтов в окне

В буфере передатчика в очереди на отправку стоят следующие байты, но они не будут отправлены, пока не будут подтверждены уже отправленные байты. Приемник посылает подтверждение и уведомляет о размере окна равным 5, то есть говорит: “В моем буфере есть 5 свободных мест. Пришли мне еще 5 байт.":

Подтверждение получения байтов и запрос на следующую порцию
Рис. 25. Подтверждение получения байтов и запрос на следующую порцию

Окно в передающем буфере сместится на 5 байт и новая порция данных будет передана приемнику:

Отправка следующей порции данных
Рис. 26. Отправка следующей порции данных

Теперь посмотрим, что произойдет, если приемник не успевает обработать все полученные данные и в его буфере свободное место только для 2-х байт:

Приемник сообщает новый размер окна
Рис. 27. Приемник сообщает новый размер окна

Передатчик готов передать следующие 5 байт информации, так как получил подтверждение от приемника. Однако приемник также уведомил передатчик, что в приемном буфере свободно только для 2-х байт, то есть сообщает следующее: “Снижай скорость передачи. Готов принять пока 2 байта.” 

И передатчик уменьшает окно и передает только 2 байта:

Передатчик снижает количество передаваемых данных
Рис. 28. Передатчик снижает количество передаваемых данных

В процессе передачи данных размер окна может постоянно меняться. Это зависит от загруженности сети и производительности передатчиков/приемников. 

Что происходит, когда в буфере приемника совсем нет места? 

Тогда приемник установит размер окна равным 0. Это означает прекратить передачу данных. 

Как же передатчик узнает, что буфер приемника снова готов к работе? 

После получения нулевого размера окна передатчик запускает специальный таймер, по истечении которого передатчик отправит пробный сегмент. Если буфер свободен, то приемник ответит на этот пробный сегмент и укажет новый размер окна, в противном случае снова укажет нулевое окно.

Итак подведем краткие итоги. 

В таблице представлены сравнение протоколов UDP и TCP,  а также функции, возложенные на транспортный уровень:

Функции

TCP

UDP

Управление потоком

Да

Нет

Контроль над ошибками

Да

Нет

Скорость

Медленный

Быстрый

Установление соединения

Да

Нет

Использование в приложениях чувствительных к задержкам данных

Нет (иногда допустимо)

Да

Использование в приложениях менее чувствительных к задержкам данных

Да 

Да (но не всегда)

Регулирование скорости передачи данных

Да

Нет

Запрос на повторную передачу потерянного или  искаженного сегмента

Да

Нет

Многоканальный

Да

Да

Контроль за перегрузками

Да

Нет

Упорядоченность (все сегменты на приеме будут собраны в правильном порядке)

Да

Нет

Вероятность потерь при передаче

Низкая

Высокая