Трехходовое квитирование

Процедура создания соединений использует флаг управления синхронизацией (SYN) и включает обмен тремя сообщениями. Этот обмен был назван трехходовым квитированием. Соединение инициируется при встрече прибывающего сегмента, содержащего SYN, и ожидающего входа TCN, которые создаются командой пользователя OPEN. Соответствие локального и внешнего сокетов определяет, когда соединение было инициировано. Соединение становится "установленным", когда номера последовательности синхронизированы в обоих направлениях. Очистка соединения также включает обмен сегментами, несущими в этом случае управляющий флаг FIN.
Протокол не делает никаких ограничений на повторное использование определенного соединения. Соединение определяется парой сокетов. Новые экземпляры соединения будут называться инкарнациями соединения. При этом возникает проблема: "Как TCP идентифицирует сегменты дубликаты из предыдущих инкарнаций соединения?" Эта проблема становится очевидной, если соединение открывается и закрывается в быстрой последовательности или прерывается в связи с нехваткой памяти, а затем восстанавл ивается.
Чтобы избежать путаницы, необходимо воспрепятствовать использованию сегментов из одной инкарнации соединения, в то время как те же самые номера последовательности от предыдущей инкарнации могут по-прежнему присутствовать в сети. Мы хотим гарантировать это, даже если TCP прерывает работу и теряет всю информацию о номерах последовательности, которые он использует. Когда создается новое соединение, используется генератор начального порядкового номера (ISN), который выбирает новый 32- разрядный ISN. Генератор связан с 32-битными часами (возможно, фиктивными), младший бит которых увеличивается каждые четыре миллисекунды. Таким образом, ISN циклически повторяется примерно каждые 4,55 часов. Так как мы предполагаем, что сегменты будут оставаться в сети не дольше, чем максимальное время жизни сегмента (MSL), и что MSL меньше 4,55 часов, то можно считать, что ISN будет уникальным.
Для каждого соединения существует номер посылаемой последовательности и номер получаемой последовательности. Начальный номер посылаемой последовательности (ISS) выбирается посылающим данные TCP, а начальный номер принимаемой последовательности (1RS) узнается во время процедуры создания соединения. Чтобы соединение было установлено или инициализировано, два TCP должны синхронизировать друг с другом начальные номера последовательностей. Это делается при обмене устанавливающими соединение сегментами, несущими управляющий бит, называемый "SYN" (от слова синхронизация), и начальные номера последовательностей. В качестве сокращения сегменты, переносящие бит SYN, также называются "SYN". Следовательно, решение требует подходящего механизма для выбора начального номера последовательности и небольшого привлечения квитирования для обмена ISN.
Синхронизация требует, чтобы каждая сторона посылала свой собственный начальный номер последовательности и получала подтверждение от другой стороны. Каждая сторона должна также получить начальный номер последовательности другой стороны и послать об этом подтверждение.
1. А —> В SYN мой номер последовательности X
2. А <—- В АСК ваш номер последовательности X
3. А <-- В SYN мой номер последовательности Y
4. А —> В АСК ваш номер последовательности Y
Так как шаги 2 и 3 обычно объединяются в одном сообщении, то последовательность называется трехходовым квитированием. На рис. 2.3 показано, как это выглядит в реальной жизни.
Трехходовое квитирование необходимо в связи с тем, что номера последовательности не связаны с глобальными часами сети, и TCP может иметь другие механизмы для выбора ISN. Получатель первого SYN не может узнать, является ли сегмент задержавшимся старым или нет, если он не помнит последний номер последовательности, использованный соединением (что не всегда возможно). Поэтому он должен запросить отправителя проверить, что TCP не создал сегмент, несущий номер последовательности, который может дублироваться старым сегментом, остающимся в сети. TCP должен оставаться спокойным в течение максимального периода жизни (MSL), прежде чем присваивать какие-либо номера последовательности при запуске или восстановлении после ошибки, при которой память используемых номеров последовательности была стерта. Для этой спецификации MSL задается равным двум минутам. Это инженерный выбор, который может быть изменен, если опыт покажет такую необходимость. Отметим, что если TCP повторно инициализирован, но сохранил в памяти номера последовательности, ему вообще не нужно ждать, он должен лишь использовать номера последовательности, превышающие использованные ранее.

Концепция времени молчания TCP

Если при аварийном прекращении работы хост не сохраняет никакой информации о последних номерах последовательности, переданных во время активного (т.е. не закрытого) соединения, при отправке любых сегментов TCP будет происходить задержка на период не менее согласованного времени MSL внутренней системы, частью которой является хост. Реализаторы TCP могут нарушать ограничение "времени молчания", но они рискуют тем, что некоторые получатели в Интернете старые данные будут принимать как новые, или отвергать новые данные как старые дубликаты.
TCP использует пространство номеров последовательности всякий раз, когда сегмент формируется и вводится в очередь сетевого вывода на хосте источника. Обнаружение дубликатов и алгоритм упорядочивания в протоколе TCP опирается на уникальное связывание данных сегмента с пространством последовательности, при условии, что номера последовательности не переберут все 2*а значения, прежде чем данные сегмента, связанные с этими номерами последовательности, будут доставлены и подтверждены получателем, и все двойные копии сегментов "исчезнут" из Интернета. Без такого предположения двум различным сегментам TCP могли бы быть присвоены одинаковые или перекрывающиеся номера последовательности, вызывая путаницу у получателя в определении, какие данные являются новыми, а какие старыми. Помните, что каждый сегмент связан с числом порядковых номеров последовательности, равным числу октетов данных в сегменте.
При обычных условиях TCP отслеживает следующий номер последовательности для отправки и самый старый, ожидающий подтверждения, чтобы избежать ошибочного использования номера последовательности, прежде чем первое использование было подтверждено. Однако это не гарантирует, что старые дублирующие данные удаляются из сети. Поэтому пространство последовательности сделано достаточно большим, чтобы сократить вероятность возникновения проблем из-за блуждающего дубликата. При двух Мбит/сек потребуется 4,5 часа для использования 23'' октетов пространства последовательности. Так как максимальное время жизни сегмента в сети, скорее всего, не превышает нескольких десятков секунд, это считается достаточной защитой для будущих сетей, даже если скорости передачи данных вырастут до десятков Мбит/сек. При 100 Мбит/сек время цикла равно 5,4 мин, что, возможно, коротковато, но все еще в пределах разумного.
Однако базовый механизм обнаружения дубликатов и алгоритм упорядочивания в TCP может не сработать, если TCP источника не сохраняет номера последовательности, которые он использовал в последнее время на данном соединении. Например, если бы TCP должен был запускать все соединения с порядкового номера 0, то после аварийного завершения и перезапуска TCP мог бы переформатировать предыдущее соединение (возможно, после разрешения полуоткрытого соединения) и послать пакеты с номерами последовательности, идентичными или перекрывающимися пакетами, все еще находящимися в сети, которые были посланы предыдущей инкарнацией того же соединения. При отсутствии информации о номерах последовательности, использованных определенным соединением, спецификация TCP рекомендует, чтобы источник делал задержку на MSL секунд, прежде чем посылать в соединение сегменты, чтобы дать время сегментам, остающимся в сети от предыдущей инкарнации соединения, исчезнуть из системы. Даже те хосты, которые могут запоминать время дня и использовать его для выбора значений начального номера последовательности, не защищены от этой проблемы (т.е. даже если учитывается время дня для выбора начального номера последовательности в каждой новой инкарнации соединения).

Генерация команды сброса

Как общее правило, команда сброса (RST) должна посылаться всякий раз, когда приходит сегмент, который, очевидно, не предназначен для текущего соединения. Команда сброса не должна посылаться, если неясно, что это именно тот случай. Ниже описаны три существующие группы состояний.
1. Если соединение не существует (CLOSED), то команда сброса (reset) посылается в ответ на любой входящий сегмент, за исключением другой команды сброса. В частности, SYN, адресованный несуществующему соединению, отбрасывается этими средствами. Если входящий сегмент имеет поле АСК, то команда сброса берет свой номер последовательности из поля сегмента АСК, иначе команда сброса имеет номер последовательности равный нулю, а поле АСК задается как сумма номера последовательности и длины входящего сегмента. Соединение остается в состоянии CLOSED.
2. Если соединение находится в любом не синхронизированном состоянии (LISTEN, SYN-SENT, SYN-RECEIVED), и входящий сегмент подтверждает что-то еще не посланное (сегмент несет неприемлемое АСК), или если входящий сегмент имеет уровень защиты или ячейку, которые не точно соответствуют уровню и ячейке, запрошенным соединением, то посылается команда сброса. Если посланный SYN еще не был подтвержден и уровень приоритета входящего сегмента выше, чем запрошенный уровень приоритета, то либо поднимается уровень локального приоритета (если допускается пользователем и системой), либо посылается команда сброса. Если уровень приоритета входящего сегмента меньше, чем запрошенный уровень приоритета, то процесс продолжается, как если бы приоритет соответствовал точно (если удаленный TCP не может поднять уровень приоритета, чтобы соответствовать точно, это будет обнаружено в следующем сегменте, который он посылает, и соединение будет прекращено). Если посланный сигнал SYN был подтвержден (возможно, в этом входящем сегменте), то уровень приоритета входящего сегмента должен точно соответствовать уровню локального приоритета. Если это не так, должна быть послана команда сброса. Если входящий сегмент имеет поле АСК, то команда сброса берет номер последовательности из поля сегмента АСК; иначе команда сброса имеет номер последовательности ноль, а поле АСК задается как сумма номера последовательности и длины входящего сегмента. Соединение остается в том же состоянии.
3. Если соединение находится в синхронизированном состоянии (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LASTACK, TIME-WAIT), то любой неприемлемый сегмент (номер последовательности вне окна или неприемлемый номер подтверждения) должен извлекать только пустой сегмент подтверждения, содержащий текущий посланный номер последовательности и подтверждение, указывающее следующий ожидаемый к получению номер последовательности, и соединение остается в том же состоянии. Если входящий сегмент имеет уровень защиты, ячейку или приоритет, которые не точно соответствуют уровню, ячейке и приоритету, запрошенным для соединения, посылается команда сброса и соединение переходит в состояние CLOSED. Команда сброса берет свой номер последовательности из поля АСК входящего сегмента.

Обработка команды сброса

Во всех состояниях, кроме SYN-SENT, все сегменты сброса (RST) контролируются проверкой их полей SEQ. Сброс будет признан действительным, если его номер последовательности находится в пределах окна. В состоянии SYN-SENT (RST получен в ответ на начальный SYN) RST является приемлемым, если поле АСК подтверждает SYN.
Получатель RST сначала проверяет его, а затем изменяет состояние. Если получатель был в состоянии LISTEN, то он его игнорирует. Если получатель был в состоянии SYN-RECErVED, а ранее — в состоянии LISTEN, то получатель возвращается в состояние LISTEN; иначе получатель прерывает соединение и переходит в состояние CLOSED. Если получатель был в другом состоянии, он прерывает соединение, уведомляет пользователя и переходит в состояние CLOSED. Закрытие соединения (CLOSE) является операцией, означающей: "У меня больше нет данных для пересылки". Понятие закрытия дуплексного соединения часто неверно интерпретируется, так как может быть не очевидно, как интерпретировать получающую сторону соединения. Мы выбрали одностороннюю интерпретацию CLOSE. Пользователи, которые делают CLOSE, могут продолжать RECEIVE (получать), пока они не получат сообщение о том, что другая сторона также CLOSED (закрыта). Таким образом, программа могла бы инициировать несколько команд SEND (послать) после команды CLOSE (закрыть), и затем продолжить получать, пока не будет получен сигнал, что команда RECEIVE (получить) не сработала, так как другая сторона закрылась (CLOSED). Мы предполагаем, что TCP будет сигнализировать пользователю, даже если нет никаких ожидающих RECEIVE и другая сторона закрыта, поэтому пользователь сможет аккуратно завершить свою работу. TCP надежно доставит все буферы, посланные до того, как соединение было закрыто, поэтому пользователю, который не ожидает возврата никаких данных, необходимо только подождать сообщения, что соединение успешно закрыто, следовательно, все его данные были получены TCP местом назначения. Пользователи должны продолжать считывание соединений, которые они закрыли для отправки, пока TCP не сообщит об отсутствии данных. Рассмотрим три существующих сценария:
1. Закрытие инициирует пользователь, приказывая TCP закрыть соединение.
2. Закрытие инициирует удаленный TCP, посылая управляющий сигнал FIN.
3. Оба пользователя закрывают соединение одновременно.
Сценарий 1: локальный пользователь инициирует закрытие
В этом случае может быть создан сегмент FIN и помещен в очередь исходящих сегментов. Никакие другие команды SEND пользователя TCP не принимает и входит в состояние FIN-WAIT-1. В этом состоянии допускаются команды RECEIVE (получить). Все сегменты, предшествующие и включающие FIN, будут посылаться повторно, пока не будет подтверждено их получение. Когда другой TCP подтвердит FIN и пошлет свою собственную команду FIN, первый TCP может подтвердить (АСК) этот FIN. Отметим, что TCP, получающий FIN, будет подтверждать (АСК), но не посылать свой собственный FIN, пока его пользователь также не закроет соединение.
Сценарий 2: TCP получает FIN из сети
Если из сети прибывает не вынужденный FIN, то получающий TCP может подтвердить его и сообщить пользователю, что соединение закрывается. Пользователь ответит командой CLOSE, затем TCP может послать FIN другому TCP после отправки всех оставшихся данных. Затем TCP ожидает, пока его собственный FIN не будет подтвержден, после чего удаляет соединение. Если подтверждение АСК не поступает после периода ожидания пользователя, соединение прерывается и об этом сообщается пользователю.
Сценарий 3: оба пользователя закрывают соединение одновременно
Одновременное закрытие пользователями на обоих концах соединения вызывает обмен сегментами FIN. Когда все сегменты, предшествующие FIN, обработаны и подтверждены, каждый TCP может подтвердить полученный FIN. После получения этих АСК оба удалят соединение.

Обмен срочной информацией

Цель механизма срочной доставки TCP состоит в том, чтобы посылающий пользователь мог стимулировать получателя принять некоторые срочные данные и разрешить получающему TCP указать получателю, что все известные в данный момент срочные данные получены пользователем.
Этот механизм позволяет в потоке данных обозначить точку как конец срочной информации. Всякий раз, когда эта точка у получающего TCP возникает перед номером получаемой последовательности (RCV.NXT), TCP должен приказать пользователю перейти в "режим срочности". Когда номер получаемой последовательности сталкивается с указателем срочности, TCP должен приказать пользователю перейти в "нормальный режим". Если указатель срочности обновляется, когда пользователь находится в "режиме срочности", обновление будет для пользователя невидимым. Метод использует поле срочности, которое переносится во всех передаваемых сегментах. Управляющий флаг URG указывает, что поле срочности имеет смысл и должно быть добавлено к номеру последовательности сегмента, чтобы породить указатель срочности. Отсутствие этого флага указывает, что ожидающих срочных данных нет.
Чтобы послать указание о срочности, пользователь должен послать также по крайней мере один октет данных. Если посылающий пользователь указывает путь доступа, то своевременность доставки срочной информации в процесс места назначения улучшается.