115
Этап установления соединения реализуется в виде трех-
шагового рукопожатия (three-way handshake). На первом шаге
TCP-модуль A посылает TCP-модулю B пакет с установленным флагом SYN и некоторым начальным значением номе-
ра_в_последовательности равным, например, 1000. TCP-модуль
B, будучи готов установить соединение, отвечает TCP-пакетом, подтверждающим правильный прием запроса и информирующим о готовности установить соединение. В нем поле но-
мер_подтверждения на 1 больше начального номера_в_после-
довательности для TCP-модуля A (в нашем примере 1001), флаг_ACK и флаг_SYN установлены в 1, установлен в 5000 на-
чальный номер_в_последовательности. На третьем шаге TCP-
модуль A подтверждает правильность приема TCP-пакета от B.
Этап двустороннего обмена данными. TCP-модуль, при-
нимающий адресованные ему данные, всегда подтверждает их прием, вычисляя значение поля номер_подтверждения в заголовке ответного TCP-пакета как сумму пришедшего номера_в_последовательности и длины правильно принятых данных. Отметим, что посылка данных к партнеру и подтверждение принятых от него данных реализуются в рамках одного TCP-пакета.
Закрытие соединения. Передающий TCP-модуль, посылает партнеру TCP-пакет с установленным флагом_FIN. Прием запроса на закрытие соединения принимающий TCP-модуль подтверждает пакетом, содержащем в своем заголовке поле номер_подтверждения, значение которого на 1 больше значения принятого номера_в_последовательности. После этого посылка каких-либо данных передающим TCP-модулем становится невозможной, однако принимающий модуль имеет данные для передачи, которые он отправляет исходному TCP-модулю и получает подтверждение на их прием. Затем TCP-модуль приемник формирует пакет с флагом_FIN, после подтверждения его приема соединение считается закрытым.
Таймеры
Таймер повторной передачи
Данный таймер взводится значением RTO (Retransmission TimeOut — интервал до повторной передачи) в момент посылки
116
TCP-пакета адресату. Если таймер окажется сброшенным в ноль до момента получения подтверждения пакета, то этот пакет должен быть послан вновь.
Ясно, что величина RTO не может быть фиксированной, т.к. TCP-пакеты до разных адресатов следуют по различным маршрутам через сети, скорость передачи данных в которых может различаться более чем в тысячи раз. Для вычисления оптимального значения RTO в каждом логическом соединении используется специальная процедура, специфицированная в RFC 793. Согласно этой процедуре, для каждого TCP-пакета измеряется величина RTT (Round Trip Time — интервал времени от момента посылки TCP-пакета до момента получения подтверждения на него). На основе измеренных RTT вычисляется величина SRTT (Smoothed RTT — сглаженный RTT) по следующей формуле:
SRTT = k*SRTT + (1 – k)*RTT,
где k — сглаживающий коэффициент (например, 0.9). Приведенная формула обеспечивает фильтрацию нетипичных (пиковых) значений измеренной величины RTT. Оптимальное значение RTO вычисляется по формуле:
RTO = min(U, max(L, p*SRTT)),
где U — ограничение сверху на значение RTO (например, 30 секунд); L — ограничение снизу на значение RTO (например, 1 секунда); p — коэффициент запаса (например, 2).
Если после повторной посылки TCP-пакета, опять не будет получено его подтверждение за интервал времени RTO, то попытки послать TCP-пакеты будут повторены (до 12 раз), но каждый раз с экспоненциально возрастающим значением RTO. Только после неудачи всей серии повторных посылок связь между партнерами будет считаться аварийно закрытой.
Таймер возобновления передачи
В ходе взаимодействия двух TCP-модулей (A и B) вполне возможна следующая ситуация:
TCP-модуль B уведомляет TCP-модуль A о невозможности приема от него данных, определяя размер_окна равным 0;
TCP-модуль A, имея данные для передачи, переходит в состояние ожидания от TCP-модуля B пакета с ненулевым разме-
ром_окна;
117
TCP-модуль B, у которого освободилось некоторое пространство в буферах, посылает модулю A TCP-пакет с ненулевым
размером_окна;
адресованный модулю A пакет теряется по какой-либо причине и оба TCP-модуля переходят в состояние бесконечного ожидания.
Средством выхода из такого тупикового состояния и служит
таймер возобновления передачи (persistence timer — настойчи-
вый таймер). Он взводится в момент получения TCP-пакета с нулевым значением поля размер_окна в его заголовке (типичное начальное значение для этого таймера — 5 секунд). Если до момента обнуления таймера не будет получено разрешение на возобновление передачи данных, то ожидающий разрешения TCPмодуль отправляет партнеру пакет, содержащий всего лишь 1 байт данных. По реакции партнера, возвращающего пакет с нулевым/ненулевым значением размера окна, TCP-модуль продолжает ожидание или возобновляет посылку данных.
Таймер закрытия связи
Протокол TCP предусматривает следующий простой прием предотвращения появления в сети TCP-пакетов, не имеющих адресатов: после закрытия логического соединения между партнерами номера портов, использовавшихся в этом соединении, остаются еще некоторый интервал времени действительными, что дает возможность долго блуждавшим по сети TCP-пакетам добраться до места назначения (где они будут просто проигнорированы). Величина этого интервала равна удвоенному времени жизни IP-сегмента (обычно, 2*15=30 секунд).
Таймеры поддержки соединения
Ниже описывается механизм, используемый для проверки ненарушенности логического соединения между TCP-модулями. Каждый TCP-модуль, участвующий в логическом соединении, через фиксированный промежуток времени (keep-alive timer), равный обычно 45 секундам, периодически отправляет партнеру пустые TCP-пакеты и ждет их подтверждения. Каждое полученное подтверждение говорит о ненарушенности соединения. Если же в течении определенного интервала времени (idle timer), рав-
118
ного обычно 360 секудам, не будет получено ни одного подтверждения, то логическое соединение считается оборванным.
Очевидно, что данный механизм имеет смысл включать в работу только тогда, когда партнеры по TCP-взаимодействию приостановили по какой-либо причине обмен данных на достаточно длительный срок (более 45 секунд).
Алгоритмы повышения эффективности
Задержка подтверждения
Задержка отсылки подтверждения принятого пакета используется для сокращения числа TCP-пакетов, которыми обмениваются партнеры по взаимодействию. Поясним эффект от такой задержки следующим примером.
Пусть клиентская часть некоторого приложения направляет серверной части некоторые данные. Серверная часть, получив данные и обработав их, должна вернуть клиенту результат. В ситуации без задержки TCP-модуль на стороне сервера, приняв пакет с данными и разместив их в своем буфере, сразу же отвечает подтверждающим пакетом, содержащим в своем заголовке и некоторый (уменьшенный) размер окна для приема последующих данных. Спустя некоторое (обычно, очень короткое) время данные из буфера передаются серверной части прикладной программы. Освобождение места в буфере заставляет TCP-модуль отправлять партнеру на стороне клиента TCP-пакет с новым (увеличившимся) размером окна. Тем временем прикладная программа, обработав полученные данные (часто за небольшое время), передает результат TCP-модулю для отсылки его клиенту, для чего модуль формирует еще один пакет. Итого: одна транзакция потребовала от TCP-модуля на стороне сервера посылки трех TCP-пакетов.
Введение же задержки при отсылке подтверждающего TCPпакета позволяет в ряде случаев уменьшить количество пакетов с трех до одного, содержащего сразу подтверждение, новый размер окна и результирующие данные. Экспериментальные исследования показали, что во многих случаях оптимальным значением задержки является 0.2 секунды. Для того, чтобы введение задержки сказывалось минимальным образом на приложения, предъяв-
119
ляющие жесткие требования к пропускной способности сети, задержка устанавливается нулевой при условии, что размер окна изменяется более чем на 35% или (в абсолютном исчислении) на удвоенный максимальный размер TCP-пакета.
Исключение малых окон
Возможны ситуации, когда прикладная программа, использующая TCP-сервис, выбирает из буфера обслуживающего ее TCP-модуля пришедшие для нее данные малыми порциями. Это приводит к генерации TCP-модулем большого количества TCPпакетов, содержащих в своих заголовках малую величину размера окна, что в свою очередь приводит к генерации на передающей данные стороне многих TCP-пакетов с короткими данными. Как результат — засорение сети короткими пакетами и снижение ее пропускной способности.
Во избежание деградации сети вследствие описанного явления используется следующий прием: TCP-пакет, информирующий посылающую данные сторону об увеличении размера окна, формируется только при выполнении одного из двух условий:
свободное место в буфере принимающего данные TCPмодуля увеличилось по крайней мере на четверть размера этого буфера;
свободное место увеличилось по крайней мере на максимальный размер TCP-пакета.
Кроме того, TCP-модуль, отправляющий данные, должен делать это большими порциями.
Исключение коротких TCP-пакетов
Засорение сети короткими TCP-пакетами возможно и в ситуации, когда прикладная программа, отправляющая данные партнеру по взаимодействию, делает это короткими порциями.
Для борьбы с этим используется следующий прием:
самая первая порция данных отправляется TCP-модулем сразу же при поступлении коротким TCP-пакетом;
все последующие накапливаются в буфере TCP-модуля, пока их общий объем не составит максимального размера TCPпакета или не будет получено подтверждение предыдущей посылки.