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

Как общее правило, команда сброса (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 указывает, что поле срочности имеет смысл и должно быть добавлено к номеру последовательности сегмента, чтобы породить указатель срочности. Отсутствие этого флага указывает, что ожидающих срочных данных нет.
Чтобы послать указание о срочности, пользователь должен послать также по крайней мере один октет данных. Если посылающий пользователь указывает путь доступа, то своевременность доставки срочной информации в процесс места назначения улучшается.

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

Окно, посылаемое в каждом сегменте, указывает диапазон номеров последовательности, которые готов принять в данный момент отправитель окна (получатель данных). Существует допущение, что это связано с доступным в этот момент пространством буфера данных для соединения.
Указание большого окна ускоряет передачу. Если поступает больше данных, чем может быть принято, они будут отбрасываться. Это приведет к излишним повторным передачам, создающим дополнительную нагрузку на сеть и TCP. Указание маленького окна может ограничить передачу данных до появления задержки прохода туда и обратно перед передачей каждого нового сегмента.
Предоставленные механизмы позволяют TCP объявлять большое окно, а потом сообщать, что оно значительно меньше, не принимая слишком много данных. Это так называемое "сжатие окна", очень обескураживает. Принцип надежности диктует, что TCP не будет сжимать окно самостоятельно, но будет готов к такому поведение со стороны другого TCP.
Посылающий TCP должен быть готов принять от пользователя и послать по крайней мере один октет новых данных, даже если окно отправки равно нулю. Посылающий TCP должен регулярно повторно посылать кадры получающему TCP, даже когда окно равно нулю. Для интервала повторной передачи рекомендуется использовать две минуты, когда размер окна равен нулю. Эта повторная передача является существенной для гарантии, что в том случае, когда оба TCP имеют нулевое окно, повторное открытие окна будет обязательно сообщено другому.
Если сегмент прибывает, когда получающий TCP имеет нулевое окно, он все равно должен послать подтверждение, показывающее его следующий ожидаемый номер последовательности и текущее окно (ноль). Посылающий TCP упаковывает данные для передачи в сегменты, которые соответствуют текущему окну, и может перепаковывать сегменты в очереди повторной передачи. Такая перепаковка не обязательна, но может оказаться полезной.
При соединении с однонаправленным потоком данных информация об окне будет переноситься в сегментах подтверждения, которые все имеют одинаковый номер, поэтому не существует способа переупорядочить их, если они приходят в беспорядке. Это не является серьезной, но позволит информации окна при случае временно основываться на старых отчетах получателя данных. Избежать этой проблемы можно, действуя на основе информации окна из сегментов, которые несут самые большие номера подтверждения (т.е. сегменты с номером подтверждения, равным или большим, чем самый большой из полученных ранее).
Процедура управления окном имеет существенное влияние на производительность коммуникации. Следующие комментарии являются предложениями для реализации.
Предложения по управлению окном Выделение очень маленького окна приводит к тому, что данные будут передаваться во множестве мелких сегментов, в то время как лучшая производительность достигается с помощью меньшего числа больших сегментов.
Одним из предложений по избавлению от маленьких окон для получателя является задержка обновления окна, пока дополнительное выделение не составит по крайней мере X процентов максимально возможного выделения для соединения (где X может быть от 20 до 40).
Другое предложение для отправителя с целью избежать отправки маленьких сегментов состоит в ожидании, пока окно не станет достаточно большим, прежде чем посылать данные. Если пользователь дает сигнал функции push, то данные должны быть отправлены, даже если это маленький сегмент.
Отметим, что подтверждения не должны задерживаться, так как это может привести к ненужным повторным передачам. Одной из стратегий является отправка подтверждения, когда прибывает маленький сегмент (не обновляя информацию об окне), и затем отправка другого подтверждения с новой информацией об окне, когда окно станет больше. Сегмент, посылаемый для проверки нулевого окна, может также начать разбиение передаваемых данных в сегменты все меньшего размера. Если сегмент, содержащий единственный октет данных, посланный для проверки нулевого окна, принимается, он поглощает один октет доступного в данный момент окна.
Если посылающий TCP просто посылает столько, сколько может, когда окно ненулевое, то передаваемые данные будут разбиты на чередующиеся большие и маленькие сегменты. Со временем случайные паузы у получателя, делающие доступным распределение окна, приведут к разбиению больших сегментов на более мелкие. Через какое-то время передача данных будет осуществляться в основном маленькими сегментами.
Суть вышеизложенного в том, что реализации TCP активно пытаются комбинировать выделение маленьких окон с большими окнами, так как механизмы управления окном ведут к появлению множества маленьких окон в простейших реализациях.
Интерфейс пользователь/ТСР
Следующее ниже функциональное описание команд TCP является в ка-кой-го степени общим, однако весь TCP должен предоставить некоторый минимальный набор служб для гарантии, что все реализации TCP могут поддерживать одну и ту же иерархию протоколов. Этот раздел определяет функциональные интерфейсы, встречающиеся во всех реализациях TCP.

Команды пользователя TCP

Следующие разделы объясняют, как работают некоторые из наиболее общих команд TCP, и дают значительно лучшее понимание ситуации при поиске неисправностей. Описанные ниже пользовательские команды определяют базовые функции, которые будет выполнять TCP для поддержки коммуникации между процессами. Хотя эти команды не обязательно будут видны, мы найдем признаки их работы в рассматриваемых примерах трассировки. Различные реализации могут изменять точный формат или предоставлять комбинации или подмножества базовых функций в одиночных вызовах. В частности, некоторые реализации могут захотеть открывать соединение автоматически при получении команды пользователя SEND (послать) или RECEIVE (получить) для данного соединения. При предоставлении средств коммуникации между процессами TCP должен не только принимать команды, но также и возвращать информацию процессам, которые он обслуживает. Она представляет собой общую информацию о соединении (т.е. прерывания, удаленное закрытие, связывание неопределенного внешнего сокета). Ответы на специальные команды пользователя указывают успех или различные виды отказов.
Мы предполагаем, что локальный TCP знает идентичность процессов, которые он обслуживает, и будет проверять полномочия процесса на использование указанного соединения. В зависимости от реализации TCP идентификаторы локальной сети и TCP для адреса источника будут поставляться либо TCP, либо протоколом нижнего уровня (например, IP). Эти свойства являются результатом рассмотрения вопросов безопасности, чтобы один TCP не смог маскировать другой, и т.д. Аналогичным образом, ни один процесс не может маскировать другой без возникновения конфликта TCP.
Если флаг "активный/пассивный" (Active/Passive) задан как пассивный, то он представляет собой вызов LISTEN для входящего соединения. Пассивное открытие может иметь либо полностью специфицированный внешний сокет, ожидающий определенное соединение, либо не специфицированный внешний сокет, ожидающий любой вызов. Полностью специфицированный пассивный вызов можно сделать активным последующим выполнением команды SEND. Блок управления передачей (ТСВ) создается и частично заполняется данными из параметров команды OPEN. На активной команде OPEN TCP сразу начнет процедуру синхронизации (т.е. создания) соединения.
Параметр задержки (если присутствует) позволяет вызывающей стороне установить задержку для всех данных, переданных TCP. Если данные не будут доставлены в место назначения в течение времени задержки, TCP прервет соединение. По умолчанию в настоящее время используется пять минут.
TCP или некоторый компонент операционной системы будет проверять полномочия пользователя на открытие соединения с указанным приоритетом или защитой/ячейкой. Отсутствие приоритета или спецификации защиты/ячейки в вызове OPEN указывает, что должны использоваться значения по умолчанию.
TCP будет принимать входящие запросы как подходящие только в том Случае, если информация защиты/ячейки в точности совпадает и если приоритет равен или выше приоритета, запрошенного в вызове OPEN.
Приоритет соединения равен большему из значений, запрошенному в вызове OPEN и полученному из входящего запроса, и фиксируется на этом значении в течение жизни соединения. Реализации могут захотеть предоставить пользователю управление этим согласованием приоритета. Например, пользователь может определять, что приоритет должен точно совпадать, или что любая попытка увеличить приоритет подтверждается пользователем.
TCP будет возвращать пользователю имя локального соединения. Имя локального соединения может затем использоваться в качестве сокращенного термина для соединения, определенного парой <локальный сокет внешний сокет>.