Шрифт:
Возникает закономерный вопрос: если транспортные и сетевые службы так похожи, то зачем нужны два разных уровня? Почему одного недостаточно? Это довольно тонкий, но ключевой вопрос. Программное обеспечение транспортного уровня запускается целиком на пользовательских устройствах, а сетевой уровень — в основном на маршрутизаторах, управляемых оператором связи (по крайней мере, в WAN). Что произойдет, если сетевой уровень будет предоставлять службу с установлением соединения, но она будет ненадежной? Что, если она часто будет терять пакеты? Что случится, если маршрутизаторы будут время от времени выходить из строя?
Все это приведет к большим трудностям. Пользователи не контролируют сетевой уровень, поэтому не смогут решить проблему плохого обслуживания, используя более совершенные маршрутизаторы или совершенствуя обработку ошибок канального уровня (просто потому, что маршрутизаторы им не принадлежат). Единственная возможность — расположить над сетевым уровнем еще один уровень, который будет улучшать QoS. Если в сети без установления соединения пакеты теряются или передаются с искажениями, транспортная подсистема обнаруживает проблему и выполняет повторную передачу. Если в сети с установлением соединения транспортная подсистема узнает, что ее сетевое соединение было внезапно прервано (без сведений о том, что случилось с передаваемыми в этот момент данными), она может установить новое соединение с удаленной транспортной подсистемой. По нему она может отправить запрос к равноранговому объекту и узнать, какие данные дошли до адресата, а какие нет. Затем транспортная подсистема может продолжить передачу с того момента, где она оборвалась.
По сути, наличие транспортного уровня делает транспортную службу более надежной, чем нижележащая сеть, которая не отличается стабильностью. Более того, транспортные примитивы могут быть реализованы в виде вызовов библиотечных процедур, чтобы не зависеть от сетевых примитивов. Сетевые вызовы варьируются в разных сетях (например, обращения в сети Ethernet без установления соединения могут значительно отличаться от обращений в сети с установлением соединения). Если скрыть сетевую службу за набором транспортных примитивов, то для изменений в сети потребуется простая замена одного набора библиотечных процедур другим. При этом он будет делать то же самое, но c помощью других служб более низкого уровня. Независимость приложений от сетевого уровня несет очевидную пользу.
Благодаря транспортному уровню прикладные программисты могут писать код согласно стандартному набору примитивов и сохранять работоспособность программ в самых разных сетях. Им не приходится учитывать разнообразные сетевые интерфейсы и уровни надежности. Если бы все сети работали идеально, имели одинаковые примитивы служб и никогда не менялись, то транспортный уровень, вероятно, был бы не нужен. Однако в реальности он выполняет ключевую функцию: изолирует верхние уровни от деталей технологии, устройства и несовершенства сети.
Именно по этой причине часто разграничивают уровни с первого по четвертый и уровни выше четвертого. Нижние уровни можно рассматривать как поставщика транспортных служб (transport service provider), а верхние уровни — как пользователя транспортных служб (transport service user). Разделение на поставщика и пользователя серьезно влияет на устройство уровней и делает транспортный уровень ключевым. Он формирует основную границу между поставщиком и пользователем надежной службы передачи данных. Именно этот уровень виден приложениям.
6.1.2. Примитивы транспортных служб
Чтобы дать пользователям доступ к транспортной службе, транспортный уровень должен совершить некоторые операции над прикладными программами, то есть предоставить транспортный интерфейс. У каждой службы он свой. В этом разделе мы прежде всего рассмотрим простой (но гипотетический) пример транспортной службы и ее интерфейса, чтобы познакомиться с основными принципами и понятиями. Следующий раздел будет посвящен реальному примеру.
Транспортная служба подобна сетевой, но имеет и некоторые существенные отличия. Главное состоит в том, что сетевая служба предназначена для моделирования служб, предоставляемых реальными сетями со всеми их особенностями. Эти сети могут терять пакеты, поэтому обычно сетевая служба ненадежна.
Транспортная служба, ориентированная на установление соединения, напротив, является стабильной. Конечно, в реальных сетях возникают ошибки, но в этом и заключается задача транспортного уровня — предоставлять надежную службу в ненадежной сети.
В качестве примера рассмотрим два процесса на одном компьютере, соединенные каналом в системе UNIX (или с помощью любого другого средства межпроцессорного взаимодействия). Эти процессы предполагают, что соединение между ними абсолютно идеально. Они не хотят знать о подтверждениях, потерянных пакетах, перегрузках и т.п. Им требуется стопроцентно надежное соединение. Процесс A помещает данные на одной стороне канала, а процесс B извлекает их на другой. Именно для этого и предназначена транспортная служба, ориентированная на установление соединения, — скрывать несовершенство сетевого обслуживания, чтобы пользовательские процессы считали, что существует безошибочный поток битов, даже если они выполняются на разных устройствах.