54. Напишите функцию, осуществляющую пересылку в IP-маршрутизаторе. У процедуры должен быть один параметр — IP-адрес. Также у нее есть доступ к глобальной таблице, представляющей собой массив из троек значений. Каждая тройка содержит следующие целочисленные значения: IP-адрес, маску подсети и исходящую линию. Функция ищет IP-адрес в таблице, используя CIDR, и возвращает номер исходящей линии.
55. Используя программы traceroute (UNIX) или tracert (Windows), исследуйте маршрут от вашего компьютера до различных университетов мира. Составьте список трансокеанских линий. Вот некоторые адреса:
www.berkeley.edu (Калифорния)
www.mit.edu (Массачусетс)
www.vu.nl (Амстердам)
www.ucl.ac.uk (Лондон)
www.usyd.edu.au (Сидней)
www.u-tokyo.ac.jp (Токио)
www.uct.ac.za (Кейптаун)
Глава 6. Транспортный уровень
Вместе с сетевым уровнем транспортный уровень составляет сердцевину всей иерархии протоколов. Сетевой уровень обеспечивает сквозную доставку пакетов при помощи дейтаграмм и виртуальных каналов. Транспортный уровень основан на сетевом и отвечает за передачу данных от процесса на устройстве-источнике до процесса на устройстве-адресате, предоставляя необходимый уровень надежности вне зависимости от физических характеристик используемых сетей. Он создает абстракции, с помощью которых приложения могут работать в сети. Без транспортного уровня вся концепция многоуровневых протоколов потеряет смысл. В данной главе мы подробно рассмотрим этот уровень, в том числе его службы и выбор подходящей схемы API, позволяющей решить проблемы надежности, подключения и перегрузок, а также протоколы (такие, как TCP и UDP) и производительность.
6.1. Транспортные службы
В следующих разделах мы познакомимся с транспортными службами. Мы рассмотрим виды служб, предоставляемых прикладному уровню. Чтобы обсуждение было более конкретным, мы разберем два набора базовых операций транспортного уровня. Сначала рассмотрим простой, но условный набор, чтобы показать основные идеи, а затем — реально применяемый в интернете интерфейс.
6.1.1. Службы, предоставляемые верхним уровням
Конечная цель транспортного уровня — предоставить эффективную, надежную и экономичную службу передачи данных своим пользователям (обычно это процессы прикладного уровня). Для этого транспортный уровень применяет службы, предоставленные сетевым уровнем. Программа и/или оборудование, выполняющие работу транспортного уровня, называются транспортной подсистемой, или транспортным объектом (transport entity). Эта подсистема может находиться в ядре операционной системы, в библиотечном модуле, загруженном сетевом приложении, в отдельном пользовательском процессе или даже в сетевой интерфейсной плате. Первые два варианта чаще всего встречаются в интернете. Логическая взаимосвязь сетевого, транспортного и прикладного уровней проиллюстрирована на илл. 6.1.
Илл. 6.1. Сетевой, транспортный и прикладной уровни
На транспортном уровне, как и на сетевом, могут быть службы, ориентированные на установление соединения, и службы без установления соединения. Транспортная служба с установлением соединения во многом похожа на аналогичную сетевую. В обоих случаях соединение проходит три этапа: установление, передача данных и разъединение.
Адресация и управление потоком на этих уровнях также похожи. Более того, даже транспортные службы без установления соединения очень напоминают аналогичные сетевые. Но важно отметить, что реализовать комбинацию транспортной службы без установления соединения и сетевой службы с установлением соединения достаточно трудно, так как для этого приходится разрывать только что созданное соединение сразу же после отправки одного пакета, а это неэффективно.
Возникает закономерный вопрос: если транспортные и сетевые службы так похожи, то зачем нужны два разных уровня? Почему одного недостаточно? Это довольно тонкий, но ключевой вопрос. Программное обеспечение транспортного уровня запускается целиком на пользовательских устройствах, а сетевой уровень — в основном на маршрутизаторах, управляемых оператором связи (по крайней мере, в WAN). Что произойдет, если сетевой уровень будет предоставлять службу с установлением соединения, но она будет ненадежной? Что, если она часто будет терять пакеты? Что случится, если маршрутизаторы будут время от времени выходить из строя?
Все это приведет к большим трудностям. Пользователи не контролируют сетевой уровень, поэтому не смогут решить проблему плохого обслуживания, используя более совершенные маршрутизаторы или совершенствуя обработку ошибок канального уровня (просто потому, что маршрутизаторы им не принадлежат). Единственная возможность — расположить над сетевым уровнем еще один уровень, который будет улучшать QoS. Если в сети без установления соединения пакеты теряются или передаются с искажениями, транспортная подсистема обнаруживает проблему и выполняет повторную передачу. Если в сети с установлением соединения транспортная подсистема узнает, что ее сетевое соединение было внезапно прервано (без сведений о том, что случилось с передаваемыми в этот момент данными), она может установить новое соединение с удаленной транспортной подсистемой. По нему она может отправить запрос к равноранговому объекту и узнать, какие данные дошли до адресата, а какие нет. Затем транспортная подсистема может продолжить передачу с того момента, где она оборвалась.
По сути, наличие транспортного уровня делает транспортную службу более надежной, чем нижележащая сеть, которая не отличается стабильностью. Более того, транспортные примитивы могут быть реализованы в виде вызовов библиотечных процедур, чтобы не зависеть от сетевых примитивов. Сетевые вызовы варьируются в разных сетях (например, обращения в сети Ethernet без установления соединения могут значительно отличаться от обращений в сети с установлением соединения). Если скрыть сетевую службу за набором транспортных примитивов, то для изменений в сети потребуется простая замена одного набора библиотечных процедур другим. При этом он будет делать то же самое, но c помощью других служб более низкого уровня. Независимость приложений от сетевого уровня несет очевидную пользу.
Благодаря транспортному уровню прикладные программисты могут писать код согласно стандартному набору примитивов и сохранять работоспособность программ в самых разных сетях. Им не приходится учитывать разнообразные сетевые интерфейсы и уровни надежности. Если бы все сети работали идеально, имели одинаковые примитивы служб и никогда не менялись, то транспортный уровень, вероятно, был бы не нужен. Однако в реальности он выполняет ключевую функцию: изолирует верхние уровни от деталей технологии, устройства и несовершенства сети.
Именно по этой причине часто разграничивают уровни с первого по четвертый и уровни выше четвертого. Нижние уровни можно рассматривать как поставщика транспортных служб (transport service provider), а верхние уровни — как пользователя транспортных служб (transport service user). Разделение на поставщика и пользователя серьезно влияет на устройство уровней и делает транспортный уровень ключевым. Он формирует основную границу между поставщиком и пользователем надежной службы передачи данных. Именно этот уровень виден приложениям.
6.1.2. Примитивы транспортных служб
Чтобы дать пользователям доступ к транспортной службе, транспортный уровень должен совершить некоторые операции над прикладными программами, то есть предоставить транспортный интерфейс. У каждой службы он свой. В этом разделе мы прежде всего рассмотрим простой (но гипотетический) пример транспортной службы и ее интерфейса, чтобы познакомиться с основными принципами и понятиями. Следующий раздел будет посвящен реальному примеру.
Транспортная служба подобна сетевой, но имеет и некоторые существенные отличия. Главное состоит в том, что сетевая служба предназначена для моделирования служб, предоставляемых реальными сетями со всеми их особенностями. Эти сети могут терять пакеты, поэтому обычно сетевая служба ненадежна.