Компьютерные сети. 6-е изд. - Эндрю Таненбаум
Шрифт:
Интервал:
Закладка:
По сути, наличие транспортного уровня делает транспортную службу более надежной, чем нижележащая сеть, которая не отличается стабильностью. Более того, транспортные примитивы могут быть реализованы в виде вызовов библиотечных процедур, чтобы не зависеть от сетевых примитивов. Сетевые вызовы варьируются в разных сетях (например, обращения в сети Ethernet без установления соединения могут значительно отличаться от обращений в сети с установлением соединения). Если скрыть сетевую службу за набором транспортных примитивов, то для изменений в сети потребуется простая замена одного набора библиотечных процедур другим. При этом он будет делать то же самое, но c помощью других служб более низкого уровня. Независимость приложений от сетевого уровня несет очевидную пользу.
Благодаря транспортному уровню прикладные программисты могут писать код согласно стандартному набору примитивов и сохранять работоспособность программ в самых разных сетях. Им не приходится учитывать разнообразные сетевые интерфейсы и уровни надежности. Если бы все сети работали идеально, имели одинаковые примитивы служб и никогда не менялись, то транспортный уровень, вероятно, был бы не нужен. Однако в реальности он выполняет ключевую функцию: изолирует верхние уровни от деталей технологии, устройства и несовершенства сети.
Именно по этой причине часто разграничивают уровни с первого по четвертый и уровни выше четвертого. Нижние уровни можно рассматривать как поставщика транспортных служб (transport service provider), а верхние уровни — как пользователя транспортных служб (transport service user). Разделение на поставщика и пользователя серьезно влияет на устройство уровней и делает транспортный уровень ключевым. Он формирует основную границу между поставщиком и пользователем надежной службы передачи данных. Именно этот уровень виден приложениям.
6.1.2. Примитивы транспортных служб
Чтобы дать пользователям доступ к транспортной службе, транспортный уровень должен совершить некоторые операции над прикладными программами, то есть предоставить транспортный интерфейс. У каждой службы он свой. В этом разделе мы прежде всего рассмотрим простой (но гипотетический) пример транспортной службы и ее интерфейса, чтобы познакомиться с основными принципами и понятиями. Следующий раздел будет посвящен реальному примеру.
Транспортная служба подобна сетевой, но имеет и некоторые существенные отличия. Главное состоит в том, что сетевая служба предназначена для моделирования служб, предоставляемых реальными сетями со всеми их особенностями. Эти сети могут терять пакеты, поэтому обычно сетевая служба ненадежна.
Транспортная служба, ориентированная на установление соединения, напротив, является стабильной. Конечно, в реальных сетях возникают ошибки, но в этом и заключается задача транспортного уровня — предоставлять надежную службу в ненадежной сети.
В качестве примера рассмотрим два процесса на одном компьютере, соединенные каналом в системе UNIX (или с помощью любого другого средства межпроцессорного взаимодействия). Эти процессы предполагают, что соединение между ними абсолютно идеально. Они не хотят знать о подтверждениях, потерянных пакетах, перегрузках и т.п. Им требуется стопроцентно надежное соединение. Процесс A помещает данные на одной стороне канала, а процесс B извлекает их на другой. Именно для этого и предназначена транспортная служба, ориентированная на установление соединения, — скрывать несовершенство сетевого обслуживания, чтобы пользовательские процессы считали, что существует безошибочный поток битов, даже если они выполняются на разных устройствах.
Кстати, транспортный уровень также может предоставлять ненадежную (дейтаграммную) службу, но о нем сказать почти нечего (разве что «это дейтаграммы»). Поэтому в данной главе мы сконцентрируемся на службе, ориентированной на установление соединения. Тем не менее есть приложения, например клиент-серверные вычислительные системы и потоковое мультимедиа, основанные на транспортных службах без установления соединения, поэтому мы их еще обсудим.
Второе различие между сетевой и транспортной службой состоит в том, для кого они предназначены. С точки зрения конечных точек сети сетевая служба используется только транспортными подсистемами. Мало кто пишет свои собственные реализации таких подсистем, и поэтому пользователи и программы почти не встречаются с чистой сетевой службой. Напротив, многие программы (а значит, и программисты) видят примитивы транспортной службы. Поэтому транспортная служба должна быть удобной и простой в использовании.
Чтобы понять работу транспортной службы, рассмотрим пять примитивов (илл. 6.2). Это максимально простой пример, но он дает представление о задачах транспортного интерфейса с установлением соединения. Интерфейс позволяет прикладным программам устанавливать, использовать и освобождать соединения, чего вполне достаточно для многих приложений.
Для того чтобы научиться использовать эти примитивы, рассмотрим систему, состоящую из сервера и нескольких удаленных клиентов. Вначале сервер выполняет примитив LISTEN — обычно для этого вызывается библиотечная процедура, которая обращается к системе. В результате сервер блокируется, пока клиент не обратится к нему. Когда клиент хочет связаться с сервером, он выполняет примитив CONNECT. Транспортная подсистема выполняет этот примитив, блокируя обратившегося к ней клиента и отсылая пакет серверу. Поле данных пакета содержит сообщение транспортного уровня, адресованное транспортной подсистеме сервера.
Примитив
Отправленный пакет
Значение
LISTEN (ОЖИДАТЬ)
(нет)
Блокировать сервер, пока какой-либо процесс не попытается соединиться
CONNECT (СОЕДИНИТЬ)
CONNECTION REQUEST (ЗАПРОС СОЕДИНЕНИЯ)
Активно пытаться установить соединение
SEND (ОТПРАВИТЬ)
ДАННЫЕ
Отправить информацию
RECEIVE (ПОЛУЧИТЬ)
(нет)
Блокировать сервер, пока не поступят данные
DISCONNECT (РАЗЪЕДИНИТЬ)
DISCONNECTION REQUEST (ЗАПРОС РАЗЪЕДИНЕНИЯ)
Прервать соединение
Илл. 6.2. Примитивы простой транспортной службы
Следует сказать пару слов о терминологии. За неимением лучшего термина, для сообщений, отправляемых одной транспортной подсистемой другой транспортной подсистеме, нам придется использовать понятие сегмент (segment). Оно используется в TCP, UDP и других интернет-протоколах. В более старых протоколах применялось громоздкое название модуль данных транспортного протокола (Transport Protocol Data Unit, TPDU). Сейчас оно практически не используется, однако вы можете встретить его в старых статьях и книгах.
Итак, сегменты, используемые транспортным уровнем, помещаются в пакеты, которыми обменивается сетевой уровень. Эти пакеты, в свою очередь, содержатся во фреймах, которые передает канальный уровень. Получив фрейм, процесс канального уровня обрабатывает его заголовок, и если адрес назначения совпадает с местом доставки, передает содержимое поля пользовательских данных наверх сетевой подсистеме. Cетевая подсистема похожим образом обрабатывает заголовок пакета и передает содержимое поля пользовательских данных пакета наверх транспортной подсистеме. Эта вложенность проиллюстрирована на илл. 6.3.
Илл. 6.3. Вложенность сегментов, пакетов и фреймов
Итак, вернемся к нашему примеру общения клиента и сервера. В результате запроса клиента CONNECT серверу отравляется сегмент, содержащий CONNECTION REQUEST (запрос соединения). Когда он прибывает, транспортная подсистема проверяет, заблокирован ли сервер примитивом LISTEN (то есть готов ли он к обработке запросов). Затем она снимает блокировку сервера и отсылает обратно клиенту