Нумерация данных
Назад | Содержание | Вперед

Номер очереди

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

Важно помнить о том, что количество номеров для очереди, хоть и велико, но ограничено. Диапазон номеров - от 0 до 2**32-1. Поскольку набор ограничен, то все арифметические операции с номерами очередей должны осуществляться по модулю 2**32. Это совсем не означает всякий раз предварительную арифметическую проверку номеров очереди на попадание в диапазон от 2**32-1 до 0. В работе с модульной арифметикой есть некие тонкости, поэтому нужно аккуратно программировать сравнение столь больших величин. Так символ '=<' означает "меньше или равно" (по модулю 2**32).

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

(a) является ли номер в подтверждении номером очереди для октетов, уже отправленных, но еще не получивших подтверждения;
(b) получили ли все октеты в сегменте подтверждение своих номеров (т.е. следует ли удалить данный сегмент из очереди на повторную посылку);
(c) содержит ли пришедший сегмент ожидаемые нами номера (т.е. "перекрывает" ли этот сегмент окно получателя).

В ответ на посылку данных протокол TCP будет получать их подтверждение. Для работы с полученным подтверждением необходимо уметь делать сравнение для

SND.UNA самого старого из номеров, не имевших подтверждения,
SND.NXT следующего номера очереди, ждущего посылки,
SEG.ACK номера подтверждения, полученного от чужой принимающей программы TCP (следующего номера очереди, ожидаемого чужой программой TCP),
SEG.SEQ номера очереди первого октета в сегменте,
SEG.LEN количества октетов в поле данных сегмента (учитывая SYN и FIN),
SEG.SEQ+SEG.LEN-1 номера очереди последнего октета из сегмента.

Новое подтверждение (называемое "подтверждением приемлемости") - это подтверждение выполнимости неравенств
SND.UNA < SEG.ACK =< SND.NXT

Сегмент из очереди повторной посылки получает полное подтверждение, если сумма его номера в очереди и длины поля данных меньше или равна номеру подтверждения из пришедшего сегмента.

При получении данных необходимо производить операции сравнения для следующих величин:

RCV.NXT следующий номер из очереди приходящих сегментов, а также левая или нижняя граница окна получения,
RCV.NXT+RCV.WND-1 номер очереди последнего сегмента, ожидаемого в приходящем сегменте, а также правая или верхняя граница окна получения,
SEG.SEQ первый номер в очереди, принесенный пришедшим сегментом,
SEG.SEQ+SEG.LEN-1 последний номер в очереди, принесенный пришедшим сегментом.

Считается, что сегмент перекрывает часть разрешенных номеров в очереди получения, если
RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND или
RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND

Первая часть этого текста смотрит, попадает ли начало сегмента на окно, а вторая часть - попадает ли в окно задняя часть сегмента. Если выполняется какая-либо часть теста, то сегмент попадает в окно.

Действительность несколько сложнее. Выбирая окно нулевой длины или сегмент нулевой длины, мы получаем четыре варианта проверки на приемлемость для приходящих сегментов

длина
сегмента
окно
получения

тест

0 0 SEG.SEQ = RCV.NXT
0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
>0 0 неприемлемо
>0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND или
RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND

Заметим, что когда окно, получения нулевое, никакие сегменты приниматься не будут за исключением ACK сегментов. Таким образом, протокол TCP может устанавливать нулевое окно получения при передаче данных и получении подтверждений. Однако даже когда окно получения нулевое, программа протокола TCP обязана обрабатывать поля RST и URG всех приходящих сегментов.

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

Управляющая информация реально находится не в поле данных сегмента. Следовательно, мы должны принять правила косвенного присвоения номеров очереди сегментам управления. SYN и FIN являются единственными управляющими сигналами, приемлемыми для такой защиты, и они используются только при открытии и закрытии соединения. Для целей поддержания очередности, сигнал SYN рассматривается как стоящий перед первым действительным октетом данных в сегменте, куда оба они были помещены. В то же время FIN считается стоящим после последнего реального октета данных в сегменте. Длина сегмента (SEG.LEN) учитывает как данные, так и номера очереди, отведенные под управление. В случае, когда присутствует SYN, значение SEG.SEQ соответствует номеру в очереди для сигнала SYN.

Выбор первоначального номера для очереди

Протокол не накладывает ограничения на многократное повторное использование конкретного соединения. Соединение задается подбором пары сегментов. Новые запросы на установление какого-либо соединения будут рассматриваться как повторные реализации этого соединения. Вследствие такого подхода возникает следующая проблема: "Как протокол TCP отличает дубликаты сегментов, оставшиеся от предыдущей реализации этого соединения?" Эта проблема становится явной, если соединение быстро открывается и закрывается несколько раз подряд, или же если соединение прерывает свою работу с потерей информации, хранившейся в оперативной памяти компьютера, и затем устанавливается повторно.

Чтобы избежать сбоя, мы должны избегать использования сегментов данной реализации соединения, когда в сети еще присутствуют те же самые номера очереди, оставшиеся от предыдущей реализации соединения. Мы желаем застраховаться от этого, даже если программа протокола TCP даст сбой и потеряет всю информацию об используемых ею номерах очередей. При создании новых соединений применяется генератор первоначальных номеров очереди (ISN), который выбирает новые 32 битные значения ISN. Генератор привязан к 32-битным часам (вероятно, фиктивным), чье значение меняется каждые 4 микросекунды. Таким образом, полный цикл часов ISN составляет примерно 4.55 часа. Поскольку мы полагаем, что сегменты будут существовать в сети не более максимального времени жизни сегмента (Maximum Segment Lifetime - MSL), и что MSL меньше, чем 4.55 часа, то мы можем с основанием полагать, что номера ISN будут уникальны.

Для каждого соединения существует номер в очереди отправления и номер в очереди получения. Первоначальный номер в очереди отправления (ISS) выбирается программой TCP, посылающей данные в этой очереди, а первоначальный номер в очереди получения (IRS) выясняется во время установления соединения.

Во время установления или инициализации какого-либо соединения обе программы протокола TCP должны синхронизировать друг с другом первоначальные номера очередей. Это осуществляется посредством обмена сегментами, устанавливающими соединения, несущими контрольный бит, называемый "SYN" (for synchronize - для синхронизации), несущими исходные номера для очередей. Для краткости, сегменты, несущие бит SYN, также называются SYN сегментами. Следовательно, решение проблемы требует приемлемого механизма для подбора первоначального номера очереди и немногочисленных сигналов подтверждения при обмене номерами ISN.

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

1) A --> B сигнал SYN: мой номер очереди X
2) A <-- B сигнал ACK: ваш номер очереди X
3) A <-- B сигнал SYN: мой номер очереди Y
4) A --> B сигнал ACK: ваш номер очереди Y

Поскольку шаги 2 и 3 можно объединить в одно сообщение, последнее называется подтверждением трех путей (трех сообщений).

Подтверждение трех путей необходимо, поскольку номера очереди не привязываются к неким глобальным часам данной компьютерной сети, и программы TCP могут иметь различные механизмы для подбора номеров ISN. Получатель первого сигнала SYN не может знать, задержался ли этот сигнал и уже устарел, или это не так, даже если получатель не помнит последний номер очереди, использованный этим соединением (что тоже не всегда возможно). Так что он должен попросить отправителя проверить этот сигнал SYN.

Период молчания

Чтобы быть уверенным в том, что программа TCP не создает сегмента, несущего номер очереди, который уже используется старым сегментом, все еще "ходящим" по сети, программа TCP должна сохранять молчание по крайней мере в течении времени жизни сегмента (MSL) до тех пор, пока она не назначит какие-либо номера очереди при запуске или восстановлении после сбоя, когда записи в памяти для прежних номеров из очереди были потеряны. В данной спецификации MSL берется равным 2 минуты.

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

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

Данная спецификация ставит условие что компьютеры, потерпевшие крах с потерей всей информации о последних номерах очередей, передаваемых по открытым (т.е. не закрытым специальной командой) соединениям, будут воздерживаться от посылки каких-либо TCP сегментов в течении по крайней мере максимального времени жизни сегмента (Maximum Segment Lifetime - MSL) в системе Internet, чей частью и является данный хост. В последующих параграфах приводится объяснение для этой спецификации. Некоторые реализации протокола TCP могут нарушать соглашение о периоде молчания, рискуя при этом тем, что некоторые получатели в системе Internet будут воспринимать старые данные как новые, или новые данные будут отброшены словно дубликаты в действительности устаревших сегментов.

Программы протокола используют новые номер очереди всякий раз, когда какой-либо сегмент формируется и помещается на хосте в очередь отправления по сети. Процедура фиксирования дубликатов и алгоритм очереди в протоколе TCP полагаются на уникальное связывание данных сегмента с местом в очереди. Номера очереди не успевают пройти весь диапазон в 2**32 значения, прежде чем связанные с ними данные из отправленного сегмента получат подтверждение от получателя, а все копии-дубликаты упомянутого сегмента покинут сеть Internet. Без этого условия можно предположить, что двум отдельным TCP сегментам могут быть назначены одинаковые или перекрывающиеся номера, что вызовет проблему у получателя при определении, какие данные являются новыми, а какие устаревшими. Напомним, что каждый сегмент привязан как ко множеству следующих друг за другом номеров очереди, так и к имеющимся в этом сегменте октетам данных.

При обычных условиях программы TCP отслеживают текущий номер очереди, подлежащий отправке, а также самое старое из ожидаемый подтверждений, что позволяет избежать ошибочного использования номера очереди, прежде чем будет получено подтверждение от более раннего использования этого же номера. Одно это не гарантирует, что старые данные - дубликаты будут удалены из сети, поэтому номера очереди сделаны очень большими, чтобы уменьшить вероятность того, что странствующие по сети дубликаты вызовут сбой по прибытии. При скорости обмена 2 мегабайта/сек очереди в 2**32 октета хватает на 4.5 часа. Поскольку максимальное время жизни сегмента в сети вряд ли превышает несколько десятков секунд, это считается достаточной защитой для будущих сетей, даже если скорости передачи данных возрастут до десятков мегабит/сек.

При скорости 100 мегабит/сек один цикл использования всех номеров очереди составляет 5.4 минуты, что может быть достаточно мало, но еще остается приемлемым.

Однако основной механизм регистрации дублей и поддержания очередей может быть отменен, если программа протокола TCP, посылающая данные, не имеет места в памяти для хранения номеров в очереди, которые она использовала в последний раз для конкретного соединения. Например, если программа TCP при создании всех соединений начинает с номера очереди 0, то при сбое и повторном запуске программа TCP может повторно сформировать прежнее соединение (возможно, после анализа наполовину открытого соединения) и послать по нему пакеты, чьи номера в очереди полностью совпадают или лишь частично перекрывают номера пакетов, которые еще присутствуют в сети и были отправлены предыдущей реализацией этого же соединения. В отсутствие сведений о номерах очереди, прежде использовавшихся для передачи информации по данному конкретному соединению, спецификация протокола TCP рекомендует отправителю воздержаться на MSL секунд от посылки сегментов по этому со единению, что даст возможность сегментам, запущенным в сеть старой реализацией соединения, покинуть систему.

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

В качестве примера предположим, что соединение открыто со стартовым номером очереди S. Предположим также, что это соединение используется не столь часто и возможно, функция определения исходного номера очереди (ISN(t)) принимает значение (скажем, S1), равное номеру последнего сегмента, отправленного данной программой TCP, по этому конкретному соединению, Теперь предположим, что именно в этот момент хост-компьютер дал сбой, восстановился и устанавливает новую реализацию этого соединения. Первоначальный номер очереди при этом будет S1=ISN(t), а это последний номер очереди в старой реализации соединения! Если восстановление произойдет достаточно быстро, то старые дубликаты, созданные с номером очереди, близким к номеру S1, могут быть получены своим адресатом и обработаны так, как будто бы это новые пакеты в новой реализации соединения.

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

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

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

Итак, каждый отправленный сегмент занимает один или несколько номеров в очереди ожидания. Номера, отведенные под сегмент, являются "занятыми" или "в работе", пока не истекут MSL секунд. При сбое определенное место в очереди в течении определенного времени продолжает оставаться занятым октетами из последнего отправленного сегмента. Если вскоре создается новое соединение и оно использует какие-либо номера из очереди в момент, когда ими еще пользуется сегмент из предыдущей реализации соединения, то следовательно эта область перекрывания номеров очередей может являться причиной проблем у получателя.

Назад | Содержание | Вперед