Управление ТСР-соединением
Несмотря tfa то что эта тема может показаться не столь увлекательной, как тема надежной передачи данных или контроля потока, она является весьма важной, поскольку процедура установления соединения способна в значительной степени увеличить время ожидания (например, при навигации в web). Итак, мы изучаем вопрос установления TCP-соединения. Пусть процесс, выполняющийся на одном хосте (клиент), желает инициировать соединение с процессом, выполняющимся на другом хосте (с сервером). Сначала клиентское приложение уведомляет TCP-клиент о том, что необходимо установить TCP-соединение с сервером. ТСР-клиент инициирует TCP-соединение следующим образом.
1. Клиентская сторона TCP отсылает серверной стороне специальный сегмент, не содержащий данных. Флаг SYN, находящийся в заголовке этого сегмента (см. рис. 3.26), установлен в 1, поэтому данный сегмент часто называют SYN-сегментом. Клиентская сторона устанавливает начальный порядковый номер (client_isn) и помещает его в поле порядкового номера SYN-сегмента. SYN-cer-мент заключается в IP-дейтаграмму и отправляется серверу.
2. Когда IP-дейтаграмма с SYN-сегментом достигает хоста сервера (если не происходит ее потери), сервер извлекает из нее SYN-сегмент, создает буфер и переменные для соединения, а затем отправляет клиенту сегмент, уведомляющий о выделении TCP-соединения. Этот сегмент также не содержит прикладных данных, однако его заголовок несет важные сведения. Во-первых, флаг SYN, как и в предыдущем сегменте, установлен в 1. Во-вторых, в поле подтверждения содержится число client_isn + 1. Наконец, в поле порядкового номера сервер указывает свой начальный порядковый номер server_isn. Если бы хосты могли общаться при помощи слов, то содержимое второго сегмента, вероятно, выглядело бы следующим образом: «Я получил Ваш SYN-сегмент с просьбой установить с Вами TCP-соединение с начальным порядковым номером client_isn. Я согласен удовлетворить эту просьбу. Мой начальный порядковый номер server_isn». Иногда второй сегмент называют SYNACK-сегментом.
3. Получив SYNACK-сегмент, клиент выделяет память для буфера и переменных TCP-соединения и отсылает серверу сегмент, подтверждающий получение SYNACK-сегмента — в поле подтверждения помещается число serveMsn + 1. Поскольку соединение уже установлено, флаг SYN сбрасывается в 0.
После выполнения перечисленных шагов клиент и сервер готовы к обмену данными друг с другом. Во всех последующих сегментах значение флага SYN равно 0. Процесс установления TCP-соединения иллюстрирует рис. 3.34. Поскольку в этом процессе клиент и сервер обмениваются тремя сегментами, процедуру установления соединения часто называют тройным рукопожатием. Некоторые аспекты тройного рукопожатия затронуты в упражнениях, приведенных в конце главы. (Для чего нужны начальные порядковые номера? Каковы причины использования тройного рукопожатия вместо двойного?) Интересно отметить, что скалолаз и тот, кто его страхует, перед началом восхождения обмениваются тройным рукопожатием, чтобы удостовериться в обоюдной готовности.
Процедура закрытия TCP-соединения подразумевает освобождение памяти, выделенной для буферов и переменных, и может происходить по инициативе любой из сторон. Так, рис. 3.35 иллюстрирует закрытие TCP-соединения клиентской стороной. Клиентский процесс генерирует команду закрытия соединения, которая приводит к отправке TCP-клиентом специального сегмента. В заголовке этого сегмента флаг FIN установлен в 1. Получив данный сегмент, сервер подтверждает это. Затем сервер отсылает клиенту завершающий сегмент, в котором бит FIN также установлен в 1; в свою очередь, получение этого сегмента подтверждается клиентом. После этого все ресурсы соединения на обеих сторонах освобождаются.
На протяжении жизни TCP-соединения каждая из сторон проходит через серию изменяющихся TCP-состояний. На рис. 3.36 приведена типичная последовательность TCP-состояний клиентской стороны. Первым состоянием клиента является состояние CLOSED; в этом состоянии происходит инициирование TCP-соединения клиентским приложением, заключающееся в создании сокета. Клиентская сторона TCP посылает серверной стороне SYN-сегмент и переходит в состояние SYN_SENT. В этом состоянии она ожидает ответного SYNACK-сегмента от сервера, в котором бит SYN установлен в 1. Получив SYNACK-сегмент, клиент входит в состояние ESTABLISHED, в котором он может принимать и отправлять сегменты, содержащие данные прикладного уровня.
Предположим, что закрытие соединения инициируется клиентской стороной (заметим, что сервер также может закрыть соединение). Клиент отправляет ТСР-сегмент с битом FIN, установленным в 1, и входит в состояние FIN_WAIT__1. В этом состоянии клиентская сторона ожидает подтверждения (АСК) для переданного сегмента. Получив подтверждение, клиент переходит в состояние FIN_WAIT_2, где ожидает получения от сервера завершающего сегмента с битом FIN, установленным в 1. Получив сегмент, клиент квитирует его и входит в состояние TIME_WAIT. Это состояние предусматривает повторную передачу подтверждения для завершающего сегмента в случае возможной потери этого подтверждения. Длительность нахождения клиента в состоянии TIME_WAIT зависит от реализации протокола, однако наиболее типичными значениями являются 30 с, 1 мин и 2 мин. После выхода из состояния TIME_WAIT происходит формальное закрытие TCP-соединения, при котором освобождаются все его ресурсы, включая номера портов.
На рис. 3.37 представлена типичная последовательность состояний серверной стороны ТСР-соединения для случая, когда закрытие соединения происходит по инициативе клиентской стороны. Переходы из одного состояния в другое понятны, и мы не будем останавливаться на их описании. Обратите внимание на то, что две приведенные диаграммы переходов соответствуют случаям, когда установление и закрытие ТСР-соединения происходит «в штатном режиме». Мы не рассматривали такие нетипичные ситуации, как, например, одновременные попытки закрыть соединение, предпринимаемые обеими сторонами. Если вас интересует описание подобных ситуаций и прочие нюансы, касающиеся протокола TCP, рекомендуем вам обратиться к дополнительным информационным ресурсам.
Итак, мы завершаем разговор о контроле потока и обнаружении ошибок в протоколе TCP. Другим важным вопросом, который нам необходимо изучить, является контроль перегрузки. В следующем разделе мы рассмотрим общие принципы контролирования перегрузки, а затем вновь вернемся к протоколу TCP для того, чтобы увидеть, каким образом изученные принципы применяются на практике.