Глава 17 TCP: Transmission Control Protocol

Введение

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

Описанию TCP посвящена эта глава, и следующие семь глав. В главе 18 будет рассказано, как устанавливаются и разрываются TCP соединения, в главе 19 и главе 20 мы рассмотрим обычную передачу данных, как в диалоговом использовании (удаленный заход), так и передачу файлов. В главе 21 мы подробно рассмотрим, как TCP осуществляет тайм-ауты и повторные передачи. И в главе 22 и главе 23 мы рассмотрим некоторые таймеры TCP. И в заключение, в главе 24 мы рассмотрим новые характеристики и производительность TCP.

Основная спецификация TCP находится в RFC 793 [Postel 1981c], однако некоторые ошибки этого RFC исправлены в требованиях к хостам Host Requirements RFC.

TCP сервисы

Несмотря на то, что TCP и UDP используют один и тот же сетевой уровень (IP), TCP предоставляет приложениям абсолютно другие сервисы, нежели UDP. TCP предоставляет основанный на соединении надежный сервис потока байтов.

Термин "основанный на соединении" (connection-oriented) означает, что два приложения, использующие TCP (как правило, это клиент и сервер), должны установить TCP соединение друг с другом, после чего у них появляется возможность обмениваться данными. Типичная аналогия - это набор телефонного номера, ожидание ответа от удаленного абонента, когда он говорит "алло", после чего необходимо сказать, кто звонит. В главе 18 мы рассмотрим, как устанавливается соединение и как это соединение разрывается через некоторое время, когда работа завершена.

Всегда существуют две конечные точки, которые общаются друг с другом с помощью TCP соединения. Концепции, о которых мы говорили в главе 12, широковещательная рассылка и групповая рассылка, не имеют отношения к TCP.

TCP обеспечивает свою надежность благодаря следующему:

- Данные от приложения разбиваются на блоки определенного размера, которые будут отправлены. Это полностью отличается от UDP, в котором каждая запись, которую осуществляет приложение, генерирует IP датаграмму этого размера. Блок информации, который передается от TCP в IP, называется сегментом (segment). (См. рисунок 1.7.) В разделе "Максимальный размер сегмента" главы 18 мы посмотрим, как TCP определяет нужный размер сегмента.
- Когда TCP посылает сегмент, он устанавливает таймер, ожидая, что с удаленного конца придет подтверждение на этот сегмент. Если подтверждение не получено по истечении времени, сегмент передается повторно. В главе 21 мы рассмотрим стратегию TCP, которую он реализует для тайм-аутов и повторных передач.
- Когда TCP принимает данные от удаленной стороны соединения, он отправляет подтверждение. Это подтверждение не отправляется немедленно, а обычно задерживается на доли секунды, что мы обсудим в разделе "Задержанные подтверждения" главы 19.
- TCP осуществляет расчет контрольной суммы для своего заголовка и данных. Это контрольная сумма, рассчитываемая на концах соединения, целью которой является выявить любое изменение данных в процессе передачи. Если сегмент прибывает с неверной контрольной суммой, TCP отбрасывает его и подтверждение не генерируется. (Ожидается, что отправитель отработает тайм-аут и осуществит повторную передачу.)
- Так как TCP сегменты передаются в виде IP датаграмм, а IP датаграммы могут прибывать беспорядочно, также беспорядочно могут прибывать и TCP сегменты. После получения данных TCP может по необходимости изменить их последовательность, в результате приложение получает данные в правильном порядке.
- Так как IP датаграмма может быть продублирована, принимающий TCP должен отбрасывать продублированные данные.
- TCP осуществляет контроль потока данных. Каждая сторона TCP соединения имеет определенное пространство буфера. TCP на принимающей стороне позволяет удаленной стороне посылать данные только в том случае, если получатель может поместить их в буфер. Это предотвращает от переполнения буферов медленных хостов быстрыми хостами.

Между двумя приложениями по TCP соединению осуществляется обмен потоком 8-битовых байтов. Автоматически TCP не вставляет записи маркеров. Это называется сервисом потока байтов (byte stream service). Если приложение на одном конце записало сначала 10 байт, затем 20 байт и затем еще 50 байт, приложение на другом конце соединения не может сказать какого размера была каждая запись. На другом конце эти 80 байт могут быть считаны, например, за 4 раза по 20 байт за каждый раз. Один конец соединения помещает поток байт в TCP, и точно так же идентичный поток байт появляется на другом конце.

TCP не интерпретирует содержимое байтов. TCP понятия не имеет о том, происходит ли обмен двоичными данными, ASCII символами, EBCDIC символами или чем-либо еще. Эта интерпретация потока байтов осуществляется приложениями на каждой стороне соединения.

Это представление потока байтов протоколом TCP напоминает представление файла в операционной системе Unix. Ядро Unix не интерпретирует байты, которые приложение читает или записывает - это полностью зависит от приложений. Ядро Unix не видит разницы между бинарными файлами и файлами, содержащими строки текста.

Заголовок TCP

Вспомним, что данные TCP инкапсулируются в IP датаграммы, как показано на рисунке 17.1.

Рисунок 17.1 Инкапсуляция TCP данных в IP датаграмму.

На рисунке 17.2 показан формат TCP заголовка. Обычно его размер составляет 20 байт, если не присутствуют опции.

Рисунок 17.2 TCP заголовок.

Каждый TCP сегмент содержит номер порта (port number) источника и назначения, с помощью которых идентифицируются отправляющее и принимающее приложения. Эти два значения вместе с IP адресом источника и назначения в IP заголовке уникально идентифицируют каждое соединение.

Комбинация IP адреса и номера порта иногда называется сокетом (socket) . Этот термин появился в исходной спецификации TCP (RFC 793), а позднее стал использоваться в качестве имени программного интерфейса Berkeley (глава 1, раздел "Интерфейсы прикладного программирования"). Эта пара сокетов (содержащая IP адрес клиента, номер порта клиента, IP адрес сервера и номер порта сервера) указывает две конечные точки, которые уникально идентифицируют каждое TCP соединение.

Номер последовательности (sequence number) идентифицирует байт в потоке данных от отправляющего TCP к принимающему TCP. Если мы представим поток байтов, текущий в одном направлении между двумя приложениями, TCP нумерует каждый байт номером последовательности. Номер последовательности представляет собой 32-битное беззнаковое число, которое переходит через 0, по достижению значения 232 - 1.

При установлении нового соединения, взводится флаг SYN. Поле номера последовательности (sequence number field) содержит исходный номер последовательности (ISN - initial sequence number), который выбирается хостом для данного соединения. Номер последовательности первого байта данных, который посылается этим хостом, будет равен ISN плюс один, потому что флаг SYN занимает собой номер последовательности. (Подробно мы опишем, как в действительности устанавливается соединение и как соединение разрывается, в следующей главе, где увидим, что флаг FIN также занимает собой номер последовательности.)

Так как каждый байт, который участвует в обмене, пронумерован, номер подтверждения (acknowledgment number) это следующий номер последовательности, который ожидает получить отправитель подтверждения. Это номер последовательности плюс 1 последнего успешно принятого байта данных. Это поле принимается в рассмотрение, только если флаг ACK (описан ниже) взведен.

Отправка ACK не стоит ничего (это означает, что на подтверждение не тратится сегмент), потому что 32-битное поле номера подтверждения всегда является частью заголовка, так же как и флаг ACK. Мы увидим, что когда соединение установлено, это поле всегда установлено и флаг ACK всегда взведен.

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

TCP может быть описан как протокол с изменяющимся окном без селективных или отрицательных подтверждений. (Изменение окна, используемое при передаче данных, описано в разделе "Изменение размера окна" главы 20.) Мы сказали, что в TCP нет селективных подтверждений, потому что номер подтверждения в TCP заголовке означает, что отправитель успешно принял, все байты за исключением этого байта. Таким образом, в настоящее время не существует возможности подтвердить отдельно выбранную часть потока данных. Например, если байты 1-1024 приняты нормально, а следующий сегмент содержит байты 2049-3072, принимающий не может подтвердить этот новый сегмент. Все что он может - это послать ACK с номером подтверждения 1025. Также нет никакого смысла посылать отрицательные подтверждения на сегмент. Например, если сегмент с байтами 1025-2048 прибыл, однако была определена ошибка в контрольной сумме, все что может послать принимающий TCP это ACK с номером подтверждения равным 1025. В разделе "Быстрая повторная передача и алгоритм быстрого восстановления" главы 21 мы увидим, как дублированные подтверждения могут помочь определить потерю пакетов.

Длина заголовка (header length) содержит длину заголовка в 32-битных словах. Это объясняется тем, что длина поля опций переменная. С 4-битным полем у TCP есть ограничение на длину заголовка в 60 байт. Без опций, однако, стандартный размер составляет 20 байт.

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

URG

  Указатель срочности (urgent pointer) будет рассмотрен в разделе "Режим срочности (Urgent Mode)" главы 20.

ACK

  Номер подтверждения необходимо принять в рассмотрение (acknowledgment).

PSH

  Получатель должен передать эти данные приложению как можно скорее (глава 20, раздел "Флаг PUSH").

RST

  Сбросить соединение (глава 18, раздел "Сегменты сброса (Reset)").

SYN

  Синхронизирующий номер последовательности для установления соединения. Этот следующий флаги описаны в главе 18.

FIN

  Отправитель заканчивает посылку данных.

Контроль потока данных TCP осуществляется на каждом конце с использованием размера окна (window size) . Это количество байт, начинающееся с указанного в поле номера подтверждения, которое приложение собирается принять. Это 16-битовое поле ограничивает размер окна в 65535 байт. В разделе "Опция масштабирования окна" главы 24 мы увидим, что опция масштабирования окна позволяет изменять это значение, при этом могут быть использованы окна большего размера.

Контрольная сумма (checksum) охватывает собой весь TCP сегмент: TCP заголовок и TCP данные. Это обязательное поле, которое должно быть рассчитано и сохранено отправителем, а затем проверено получателем. Контрольная сумма TCP рассчитывается так же как контрольная сумма UDP, с использованием псевдозаголовка, как описано в разделе "Контрольная сумма UDP" главы 11.

Указатель срочности (urgent pointer) действителен только в том случае, если установлен флаг URG. Этот указатель является положительным смещением, которое должно быть прибавлено к полю номера последовательности сегмента, чтобы получить номер последовательности последнего байта срочных данных. Режим срочности TCP это способ, с помощью которого отправитель передает срочные данные на удаленный конец. Мы рассмотрим эту характеристику в разделе "Режим срочности (Urgent Mode)" главы 20.

Наиболее общее поле опций - это опция максимального размера сегмента (MSS - maximum segment size). На каждом конце соединения эта опция обычно указывается в первом сегменте, с которого начинается обмен (сегмент с установленным флагом SYN, который используется для установления соединения). Она указывает на максимальный размер сегмента, который может быть принят отправителем. Мы опишем опцию MSS более подробно в разделе "Максимальный размер сегмента" главы 18, а некоторые другие опции TCP в главе 24.

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

Краткие выводы

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

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

TCP используется множеством популярных приложений, таких Telnet, Rlogin, FTP и электронная почта (SMTP).

Упражнения

Мы рассмотрели следующие форматы пакетов, каждый из которых имеет контрольную сумму в своем заголовке: IP, ICMP, IGMP, UDP и TCP. Для каждого опишите, какая часть IP датаграммы покрывается контрольной суммой, и где контрольная сумма обязательна, а где нет.
- Почему все протоколы Internet, которые мы обсуждали (IP, ICMP, IGMP, UDP, TCP), молча отбрасывают пакеты, которые прибывают с ошибкой контрольной суммы?
- TCP предоставляет сервис потока байтов, где не происходит разграничения записей в процессе передачи между отправителем и получателем. Как могут приложения осуществить вставку своих собственных маркеров записей?
- Почему номера портов источника и назначения находятся в начале TCP заголовка?
- Почему TCP заголовок имеет поле длины заголовка, тогда как UDP заголовок (рисунок 11.2) не имеет?