Как упоминалось в предыдущей главе, TCP/IP — это не просто один-два протокола; обычно реализуется сразу целый набор протоколов, или, как иногда называют, стек протоколов. В предыдущей главе мы познакомились с соответствием между протоколами из стека TCP/IP и эталонной моделью OSI, но теперь рассмотрим этот стек более подробно. Как можно видеть на рис, стек TCP/IP состоит из четырех уровней: уровень приложений, транспортный уровень, уровень Интернета и сетевой уровень. В совокупности эти четыре уровня охватывают все функции модели OSI.
Внизу стека находится уровень сетевого интерфейса, который соответствует физическому уровню модели OSI. Этот уровень отвечает за перенос кадров в среду передачи и за извлечение кадров из среды передачи. Необходимо отметить, что это независимый от среды передачи уровень. Не имеет значения, будет ли это медный провод, волоконно-оптический кабель, лазер, инфракрасные лучи или радио. Кроме того, он не зависит от метода доступа к среде. Поэтому в локальной вычислительной сети (LAN) стек TCP/IP можно использовать поверх Ethernet, Token Ring или FDDI, и, конечно, можно использовать TCP/IP совместно с различными технологиями глобальных сетей (WAN), таких как последовательный канал, использующий старый протокол SLIP, или протокол РРР, который был создан как усовершенствование старого стандарта SLIP. РРР предоставляет службы канального уровня, которые включают обнаружение ошибок, управление конфигурацией, а также методы безопасности. Другим типом технологий WAN является коммутация пакетов, например Frame Relay или ATM.
Следующим уровнем снизу является уровень Интернета, который предоставляет функции, соответствующие второму (канальному) и третьему (сетевому) уровням модели OSI. Уровень Интернета отвечает за инкапсуляцию пакетов в дейтаграммы IP и выполняет все необходимые алгоритмы маршрутизации. Здесь имеются четыре протокола IP: протокол управляющих сообщений Интернета (Internet Control Message Protocol, iCMP), протокол управления группами Интернет (Internet Group Management Protocol, IGMP), протокол Интернет (Internet Protocol, IP) и протокол преобразования адресов (Address Resolution Protocol, ARP). Протокол ICMP используется для отправки сообщений и сообщений об ошибках относительно доставки пакетов. Он осуществляет это от имени IP. ICMP не делает IP "надежным" протоколом, но он может предоставить определенный уровень обратной связи по специальным условиям. Сами сообщения ICMP переносятся как дейтаграммы, т.е. без обеспечения надежности. Следующим протоколом, представленным на этом уровне, является IGMP. Он используется компьютерами для сообщения о своем членстве в определенной группе, чтобы получать широковещательные рассылки от маршрутизаторов, которые поддерживают широковещание. Эти рассылки передаются как дейтаграммы, т.е. являются ненадежной формой коммуникации. Последними двумя протоколами Интернета, о которых необходимо сказать, являются IP и ARP. В связи с важностью сетевой коммуникации мы рассмотрим их более детально. Остановимся сначала на протоколе IP.
IP отвечает за адресацию и маршрутизацию пакетов между компьютерами и сетями. (Каждое устройство в сети IP, имеющее IP-адрес, называется хостом; иногда хостами называют компьютеры, маршрутизаторы, принтеры и даже управляемые концентраторы.) Именно поэтому адрес, присвоенный хосту, поддерживающему стек TCP/IP, называется IP-адресом. Это протокол без поддержки соединения, т.е. он не создает сеанс перед передачей данных. В этом отношении он является ненадежным протоколом, так как не гарантирует доставку, не требуя подтверждения, что данные получены в месте назначения. Следующим протоколом уровня Интернета является протокол ARP.
ARP используется для поиска аппаратного адреса машины в сети. Этот адрес, называемый иногда адресом МАС или адресом платы Ethernet, требуется, если два компьютера собираются общаться друг с другом. Адрес МАС должен быть преобразован в адрес IP, чтобы хосты общались с помощью протокола IP. ?RP преобразует адрес с помощью широковещательной рассылки для всех хостов в локальной сети. Компьютер места назначения будет отвечать пакетом, который содержит IP-адрес и адрес МАС. Эта информация будет затем храниться в кэше ARP на локальной машине. Последующая информация предназначена для удаленного хоста; сначала будет проверяться кэш ARP, а затем посылаться другое широковещательное сообщение.
Второй уровень сверху является транспортным уровнем, отвечающим за обеспечение сеансов коммуникации между компьютерами. В стеке существуют два транспортных протокола. Это протокол управления передачей (Transmission Control Protocol, TCP) и протокол пользовательских дейтаграмм (User Datagram Protocol, UDP). Для наличия двух транспортных протоколов в стеке есть серьезная причина, так как они работают по-разному. ТСР является протоколом с поддержкой соединения, т.е. сначала он создает соединение с другой машиной. Используемый, когда требуется надежное соединение, он обеспечивает подтверждение доставки каждого пакета. Если подтверждение не получено, то посылающий компьютер пошлет информацию повторно. С другой стороны, UDP является протоколом без поддержки соединения, он не требует соединения и не гарантирует доставку пакета. Это протокол, работающий без гарантии доставки: он оставляет задачу отслеживания пакетов и управление потоком данных приложению, которое обращается к транспортному уровню.
Вверху модели находится уровень приложений. В стандартной реализации стека протоколов TCP/IP на этом уровне существует множество утилит. Такие протоколы, как FTP (File Transfer Protocol, протокол передачи файлов), Telnet, SNMP (Simple Network Management Protocol, простой протокол управления сетью), DNS (служба имен доменов) находятся на этом уровне, так как именно здесь приложения получают доступ к сети. В реализации TCP/IP компании Microsoft есть два способа, которыми приложения могут получить доступ к сети: либо через NetBIOS, либо через Windows Sockets. Интерфейс NetBIOS позволяет протоколам TCP/IP или NetBEUI использовать службы именования и сообщений, используя соглашение об именах NetBIOS, в то время как служба Windows Sockets предоставляет интерфейс прикладного программирования (API) для транспортных протоколов, таких как TCP/IP или IPX.
Созданное соединение называют "полуоткрытым", если один из TCP закрыл или прервал соединение на своем конце в одностороннем порядке, или если два конца соединения стали десинхронизированными в связи с аварийным отключением, которое привело к потере памяти. Такие соединения будут автоматически восстанавливаться при пытке послать данные в любом направлении. Однако полуоткрытые соединения считаются аномальными, и постепенно включается процедура восстановления. Если соединение узла А больше не существует, то попытка пользователя узла В послать ему какие-либо данные приведет к тому, что TCP узла В получит управляющее сообщение сброса в исходное состояние (reset). Такое сообщение указывает TCP узла В на ошибку, и ожидается прерывание соединения.
Предположим, что два пользовательских процесса А и В общаются друг с другом, когда происходит авария, вызывая потерю памяти TCP процесса А. В зависимости от операционной системы, поддерживающей TCP процесса А, скорее всего, существует некоторый механизм восстановления ошибок. Когда TCP снова включен, А начнет соединение заново или с точки восстановления. В результате А будет пытаться снова открыть (OPEN) соединение или послать (SEND) в соединение, которое он считает открытым. В последнем случае он получает от локального (A) TCP сообщение "соединение не открыто". При попытке создать соединение TCP процесса А пошлет сегмент, содержащий SYN.
Во всех состояниях, кроме 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.
