1.5. Сетевые протоколы

Мы начнем этот раздел с обсуждения целей разработки сетевых протоколов, затем изучим основную концепцию, применяемую при их создании, — разделение на уровни. Далее мы сравним службы, ориентированные на установление соединения, и службы без установления соединений, а также поговорим о примитивах служб, необходимых для их работы.


1.5.1. Цели проектирования

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


Надежность

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

Надежность — это свойство сети, работающей должным образом, даже если составляющие ее компоненты ненадежны. Представьте себе биты передаваемого по сети пакета. Вполне вероятно, что часть этих битов будет получена приемником в искаженном (инвертированном) виде вследствие скачка электричества, случайных беспроводных сигналов, изъянов в аппаратном обеспечении, ошибок программного обеспечения и т.д. Как же найти и исправить эти ошибки?

Один из механизмов поиска ошибок в полученной информации — использование кодов обнаружения ошибок (error detection). Полученная в искаженном виде информация отправляется заново до тех пор, пока не будет принята в правильном виде. Существуют также более мощные коды исправления ошибок (error correction). С их помощью правильное сообщение восстанавливается на основе полученных (возможно, неправильных) битов информации. Оба этих механизма основаны на добавлении избыточной информации в сообщение. Они применяются на низших уровнях (для защиты отправляемых по отдельным каналам пакетов) и на высших уровнях (для проверки корректности полученного содержимого).

Еще одна задача в обеспечении надежности — поиск работоспособного пути передачи данных по сети. Зачастую между источником и приемником существует несколько путей, а в большой сети некоторые каналы или маршрутизаторы могут не работать. К примеру, сеть в Берлине вышла из строя. Пакеты, отправленные из Лондона в Рим через Берлин, не пройдут, но вместо этого можно отправить пакеты из Лондона в Рим через Париж. Сеть должна принимать подобные решения автоматически. Это называется маршрутизацией (routing).


Распределение ресурсов

Вторая задача проектирования сетей — распределение ресурсов. С увеличением размеров сетей возникают новые проблемы. В крупных городах нередки транспортные пробки, нехватка телефонных номеров, а еще в них можно легко потеряться. Мало кто сталкивается с этими проблемами в родном дворе, но в масштабах всего города они могут оказаться очень серьезными. Архитектуры, сохраняющие должную работоспособность сети при ее росте, называются масштабируемыми (scalable). Сети предоставляют хостам услуги на основе имеющихся ресурсов, например пропускной способности линий передачи. Чтобы один хост не слишком мешал другому, необходимы механизмы разделения ресурсов.

Часто пропускная полоса сети делится между хостами динамически, в соответствии с их потребностями. Это делается вместо того, чтобы выделять каждому хосту фиксированную часть полосы, которую он может и не использовать. Подобная архитектура называется статистическим мультиплексированием (statistical multiplexing) — ресурсы распределяются в соответствии со статистикой запросов на них. Она может применяться на низших уровнях для отдельных соединений, на высших уровнях для сети или даже для использующих сеть приложений.

Проблема, возникающая на всех уровнях: как не допустить, чтобы быстрый отправитель перегрузил данными медленного получателя. Для ее решения часто используется обратная связь от получателя отправителю. Это называется управлением потоком (flow control). Иногда в сети возникает проблема перегрузки (congestion), поскольку множество компьютеров отправляет слишком большой объем трафика и сеть не может обеспечить его доставку. Решить проблему можно путем сокращения всеми компьютерами запроса ресурсов (то есть полосы пропускания). Этот способ можно использовать на всех уровнях.

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


Способность к развитию

Еще одна задача проектирования связана с эволюцией сети. С течением времени сеть растет и возникают новые элементы, требующие подключения к ней. В последнее время применяется ключевой механизм поддержки изменений, работающий за счет разбиения общей задачи на составные части и сокрытия нюансов реализации, — разделение протокола на уровни (protocol layering). Разработчикам сетей доступно также множество других стратегий.

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

При росте сетей возникает проблема различных ограничений у разных сетевых технологий. Например, не все каналы связи сохраняют порядок отправляемых по ним сообщений, поэтому сообщения приходится нумеровать. Еще одна проблема — несовпадение максимального размера сообщений, которые могут быть переданы в разных сетях. Вследствие этого приходится создавать механизмы для разбиения сообщений на части, передачи и последующей их сборки. Это называется организацией межсетевого взаимодействия (internetworking).


Безопасность

Наконец, важная задача — обеспечить безопасность сети путем защиты ее от разнообразных угроз. Одна из таких угроз, перехват данных, уже была упомянута ранее. От этой угрозы защищают механизмы обеспечения секретности информации (confidentiality), используемые на многих уровнях. Также существуют механизмы аутентификации (authentication), гарантирующие, что никто не сможет выдать себя за кого-то другого. Они позволяют отличить поддельные сайты банков от настоящих, а сотовая сеть с их помощью может проверить, что звонок действительно поступил с вашего телефона, чтобы выставить вам счет. Механизмы обеспечения целостности (integrity) предотвращают внесение скрытых изменений в сообщения, например, замену сообщения «Списать с моего счета $10» на «Списать с моего счета $1000». Все эти возможности основаны на криптографии, которая будет рассмотрена в главе 8.


1.5.2. Разделение протокола на уровни

Для упрощения архитектуры большинство сетей организованы в виде пирамиды уровней (levels), или слоев (layers), каждый из которых построен на основе нижележащего. Количество, названия, содержимое и функции каждого уровня различаются в зависимости от сети. Задача каждого уровня состоит в предоставлении определенных служб вышележащим уровням, при одновременном сокрытии от них деталей фактической реализации служб. В определенном смысле каждый уровень представляет собой некую виртуальную машину, предлагающую службы расположенному выше уровню.

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

Правила и соглашения, касающиеся обмена информацией между уровнем n одного устройства и уровнем n другого, известны под общим названием «протокол уровня n». По сути, протокол представляет собой соглашение о том, как должно происходить взаимодействие между участниками обмена данными. Приведем аналогию. Когда женщину представляют мужчине, она может протянуть ему руку. Он же, в свою очередь, может эту руку либо пожать, либо поцеловать, в зависимости от того, является ли она американским юристом на деловой встрече или европейской принцессой на официальном балу. Нарушение протокола затрудняет общение, а то и вовсе делает его невозможным.

На илл. 1.25 приведена пятиуровневая сеть. Сущности, образующие соответствующие уровни на различных компьютерах, называются пирами (peers). Пиры могут быть программными процессами, аппаратными устройствами и даже людьми. Именно они взаимодействуют друг с другом с помощью протокола.

Илл. 1.25. Уровни, производители данных и интерфейсы

На самом деле никакие данные не передаются напрямую с уровня n одного устройства на уровень n другого. Вместо этого каждый уровень отправляет данные и управляющую информацию на уровень, лежащий непосредственно под ним, пока не будет достигнут самый низший уровень. Под уровнем 1 располагается физическая среда (physical medium), через которую происходит фактический обмен информацией. На илл. 1.25 виртуальный обмен информацией показан пунктирными линиями, а фактический — сплошными.

Каждая пара смежных уровней связана интерфейсом. Он определяет, какие базовые операции и службы предоставляет низший уровень высшему. После того как архитекторы сети задали количество и функции уровней сети, одна из важнейших задач — создание понятных интерфейсов между ними. Для этого необходимо, чтобы каждый уровень выполнял конкретный набор четко определенных функций. Помимо минимизации объемов передаваемой между уровнями информации, четко заданные интерфейсы упрощают перевод уровня на совершенно другой протокол или реализацию. Например, можно представить себе замену всех телефонных линий спутниковыми каналами, поскольку единственное, что требуется от нового протокола (или реализации), — предоставление «соседу» сверху прежнего набора служб. Хосты нередко используют разные реализации одного протокола (зачастую написанные различными компаниями). На самом деле протокол на каком-либо уровне может поменяться совершенно незаметно для уровней над и под ним.

Набор уровней и протоколов называется архитектурой сети. Спецификация архитектуры должна включать достаточное количество информации. Тогда тот, кто будет заниматься внедрением, сможет написать программу или создать аппаратное обеспечение для каждого уровня, должным образом следующие соответствующему протоколу. Впрочем, ни нюансы реализации, ни спецификация интерфейсов не являются составными частями архитектуры, поскольку они скрыты внутри устройств и не видны извне. Интерфейсы на всех компьютерах сети даже могут быть разными, главное, чтобы каждый компьютер мог правильно использовать все протоколы. Список используемых конкретной системой протоколов, по одному на уровень, называется стеком протоколов (protocol stack). Архитектуры сетей, стеки протоколов и сами протоколы являются основными темами данной книги.

Можно пояснить идею многоуровневой связи с помощью аналогии. Представьте себе двух философов (одноранговые процессы на уровне 3), один из которых разговаривает на урду и русском, а второй — на китайском и французском. Поскольку общего языка у них нет, они оба нанимают переводчиков (процесс на уровне 2), каждый из которых, в свою очередь, связывается с секретарем (процесс на уровне 1). Философ 1 хочет донести до коллеги свою любовь к oryctolagus cuniculus9. Для этого он передает своему переводчику сообщение (на русском языке) через интерфейс уровней 2/3: «Мне нравятся кролики» (илл. 1.26). Переводчики договорились насчет известного им обоим нейтрального языка, голландского, так что сообщение преобразуется в «Ik vind konijnen leuk». Выбор языка — протокол уровня 2, определяемый процессами уровня 2.

Далее переводчик отдает сообщение секретарю для дальнейшей передачи, например, по факсу (протокол уровня 1). Когда сообщение доходит до второго секретаря, он передает его второму переводчику, который переводит это сообщение на французский и передает через интерфейс 2/3 второму философу. Обратите внимание, что все протоколы совершенно не зависят от остальных, главное, чтобы интерфейсы не менялись. Переводчики могут в любой момент сменить голландский на, скажем, финский, если они оба согласны на это и ни один из них не меняет свои интерфейсы с уровнями 1 и 3. Аналогично секретари могут начать использовать вместо факса телефон, не затрагивая (и даже не оповещая) другие уровни. Любой процесс может добавлять какую-либо информацию, предназначенную только для одноуровневого с ним процесса. Эта информация не передается более высоким уровням.

Теперь рассмотрим более технический пример: как обеспечить связь для верхнего уровня пятиуровневой сети на илл. 1.27? Один из прикладных процессов, работающий на уровне 5, генерирует сообщение M и отдает его на уровень 4 для передачи. На уровне 4 перед сообщением вставляется заголовок (header) для его идентификации, а затем результат передается на уровень 3. Заголовок включает

Илл. 1.26. Архитектура «философ — переводчик — секретарь»

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

Во многих сетях размер сообщения, передаваемого по протоколу уровня 4, не ограничивается, но протокол уровня 3 налагает ограничения практически всегда. Вследствие этого уровню 3 приходится разбивать входящие сообщения на меньшие куски (пакеты), добавляя перед каждым из них заголовок уровня 3. В нашем примере сообщение M разбивается на две части, M1 и M2, пересылаемые отдельно.

Уровень 3 выбирает используемую исходящую линию связи и передает пакеты уровню 2. Уровень 2 добавляет в каждую часть сообщения не только заголовок, но и концевую метку, после чего передает полученный результат уровню 1 для физической передачи. На принимающем устройстве сообщение движется снизу вверх, с уровня на уровень, с удалением заголовков по мере продвижения. На уровень n не попадает ни один заголовок расположенных ниже n уровней.

Илл. 1.27. Пример потока данных при гипотетическом обмене информацией между уровнями 5

Глядя на илл. 1.27, важно понимать взаимосвязь между виртуальным и фактическим обменом данными, а также разницу между протоколами и интерфейсами. Например, одноранговые процессы на уровне 4 концептуально «считают», что обмениваются информацией «горизонтально», по протоколу уровня 4. В каждом из них, вероятно, есть процедуры с названиями наподобие SendToOtherSide (ОтправитьНаДругуюСторону) и GetFromOherSide (ПолучитьОтДругойСтороны), хотя на самом деле эти процедуры взаимодействуют с низшими уровнями через интерфейс 3/4, а не с другой стороной.

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

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


1.5.3. Соединения и надежность

Нижележащие уровни предоставляют расположенным выше уровням два типа служб: с соединениями и без. Степень надежности также может отличаться.


Службы, ориентированные на установление соединения

Службы, ориентированные на установление соединения (connection-oriented service), строятся по принципу телефонных систем. Чтобы с кем-то пообщаться, необходимо поднять трубку телефона, набрать номер, поговорить, а затем повесить трубку. Аналогично работает и служба: сначала она устанавливает соединение, затем использует и, наконец, освобождает его. Соединение ведет себя подобно трубе: отправитель вставляет объекты (биты) с одного ее конца, а получатель вытаскивает их с другого. В большинстве случаев очередность сохраняется, так что биты приходят в том порядке, в каком были отправлены.

В некоторых случаях при установке соединения отправитель, получатель и подсеть проводят согласование (negotiation) используемых параметров, например максимального размера сообщения, требуемого QoS и других вопросов. Обычно при этом одна сторона выдвигает предложение, а вторая может его принять, отвергнуть или внести встречное предложение. Соединение вместе с соответствующими ему ресурсами также называется каналом или линией (circuit). Это название пошло от телефонных сетей, где линией (каналом) связи назывался путь по медным проводам, по которым передавался телефонный разговор.


Службы без установления соединений

В противоположность службам, ориентированным на установление соединения, службы без установления соединений (connectionless) строятся по принципу работы обычной почты. Каждое сообщение (письмо) содержит полный адрес назначения и проходит через промежуточные узлы внутри системы независимо от всех последующих сообщений. В различных контекстах такие сообщения называются по-разному; сообщение на сетевом уровне называется пакетом. Вариант, при котором промежуточные узлы получают сообщение полностью, прежде чем отправлять его следующему узлу, называется коммутацией с промежуточным хранением данных (store-and-forward switching). Альтернативный вариант, при котором узел начинает передачу сообщения далее вплоть до полного его получения, называется сквозной коммутацией (cut-through switching). Когда два сообщения отправляются в один пункт назначения, то обычно первое отправленное первым и прибывает. Впрочем, оно может задержаться в пути, тогда первым прибудет второе.

Устанавливать соединение нужно не для всех приложений. Например, спамеры отправляют нежелательную электронную почту сразу множеству адресатов. Ненадежные (то есть без подтверждения получения) службы называются службами отправки дейтаграмм (datagram service), по аналогии с отправкой телеграмм, при которой отправитель тоже не получает уведомления о доставке.


Надежность

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

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

Существуют два незначительно отличающихся варианта надежных служб с установлением соединения: последовательность сообщений (message sequences) и байтовые потоки (byte streams). В первом варианте сохраняются границы сообщений. Если было отправлено два сообщения по 1024 байта, они прибудут в место назначения в виде двух сообщений по 1024 байта, а не одного сообщения в 2048 байт. Во втором варианте соединение представляет собой просто поток байтов, без каких-либо границ сообщений. Когда в приемник поступает 2048 байт, нет никакой возможности определить, представляли ли они собой при отправке одно сообщение из 2048 байт, два сообщения по 1024 байта или 2048 сообщений по 1 байту. При отправке по сети страниц книги для фотонабора в виде отдельных сообщений сохранение границ может играть важную роль. С другой стороны, для скачивания фильма байтовый поток с сервера на компьютер пользователя — как раз то, что нужно. Границы сообщений (отдельных кадров) внутри фильма не имеют значения.

В некоторых случаях неудобно создавать соединение для отправки одного-единственного сообщения, но важна надежность. Для подобных сценариев подойдет служба отправки дейтаграмм с подтверждением получения (acknowledged datagram service). Она напоминает отправку заказного письма с уведомлением о вручении. Получив уведомление, отправитель может быть полностью уверен в том, что письмо было доставлено по адресу и не потерялось по дороге. Один из примеров такой службы — доставка текстовых сообщений на мобильных телефонах.

Сама идея использования ненадежных коммуникаций может сначала привести в недоумение. В конце концов, как можно предпочесть ненадежную связь надежной? Прежде всего, надежная связь (в нашем понимании — с подтверждением получения) может оказаться недоступной на конкретном уровне. Например, Ethernet не обеспечивает надежного обмена данными. Пакеты периодически могут повреждаться в пути, а обеспечить их восстановление должны протоколы более высоких уровней. В частности, многие надежные службы строятся поверх ненадежных служб отправки дейтаграмм. Кроме того, присущие надежным службам задержки могут оказаться неприемлемыми, особенно для работающих в режиме реального времени приложений (например, мультимедийных). Поэтому и надежные, и ненадежные виды коммуникаций существуют параллельно.

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

Еще один вид служб — запрос/ответ (request-reply). Отправитель передает одну дейтаграмму с запросом и получает дейтаграмму с ответом. С помощью схемы «запрос/ответ» часто реализуется связь в клиент-серверной модели: клиент отправляет запрос, а сервер на него реагирует. Например, клиент с мобильного телефона отправляет запрос картографическому серверу, чтобы получить список ближайших китайских ресторанов, а сервер присылает ему этот список.

На илл. 1.28 приведена краткая сводка представленных выше типов служб.

Илл. 1.28. Шесть различных типов служб


1.5.4. Примитивы служб

Службы формально описываются набором примитивов (primitives), то есть операций, доступных обращающимся к ним пользовательским процессам. С помощью этих примитивов можно указать службе выполнить какое-либо действие или сообщить о действии, которое совершил объект на том же уровне. Если стек протоколов располагается в операционной системе (как это обычно и бывает), примитивы представляют собой системные вызовы. Такой вызов приводит к системному прерыванию в привилегированном режиме. Далее управление компьютером передается операционной системе для отправки нужных пакетов.

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

Примитив

Значение

LISTEN (прослушивать)

Блокирующее ожидание входящего соединения

CONNECT (подключиться)

Установка соединения с находящимся в состоянии ожидания одноранговым процессом

ACCEPT (согласиться)

Принятие входящего соединения от однорангового процесса

RECEIVE (принять)

Блокирующее ожидание входящего сообщения

SEND (отправить)

Отправка сообщения одноранговому процессу

DISCONNECT (отключиться)

Завершение соединения

Илл. 1.29. Простая, ориентированная на установление соединения служба с шестью примитивами

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

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

Далее клиентский процесс выполняет CONNECT, чтобы установить соединение с сервером. В вызове CONNECT должно быть указано, с кем соединяться, поэтому у него может быть параметр для адреса сервера. После этого операционная система отправляет пакет одноуровневому процессу с запросом на соединение, как показано в (1) на илл. 1.30. Клиентский процесс приостанавливается до получения ответа.

Илл. 1.30. Простое взаимодействие типа «клиент-сервер» получения дейтаграмм с подтверждением

Когда пакет прибывает на сервер, операционная система видит, что он запрашивает соединение. Она проверяет наличие прослушивающего процесса и разблокирует его, если он есть. Далее серверный процесс может устанавливать соединение при помощи вызова ACCEPT, в результате которого клиентскому процессу отправляется ответ (2) с согласием на соединение. Поступление этого ответа приводит к снятию блокировки с клиента. И сервер, и клиент в этот момент уже работают, и между ними установлено соединение.

Очевидна аналогия между этим протоколом и звонком покупателя в службу поддержки какой-либо компании. В начале дня менеджер по работе с клиентами сидит возле своего телефона в ожидании звонков. Затем звонит клиент. Когда менеджер поднимает трубку — устанавливается соединение.

Следующий шаг: выполнение сервером операции RECEIVE для подготовки к получению первого запроса. Обычно сервер делает это сразу же после снятия блокировки примитивом LISTEN, прежде чем клиент получит подтверждение. Вызов RECEIVE блокирует сервер.

Далее клиент выполняет примитив SEND для передачи своего запроса (3) с последующим RECEIVE для получения ответа. Поступление пакета с запросом разблокирует сервер, и он может обработать запрос. После завершения необходимых действий сервер отправляет ответ клиенту (4) с помощью примитива SEND. Получение этого пакета разблокирует клиента, который теперь может обработать ответ и отправить дополнительные запросы, если таковые у него есть.

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

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

Учитывая, что для одного цикла этого протокола требуется шесть пакетов, может показаться странным, что взамен него не используется протокол без установления соединения. Конечно, в идеальном мире так бы и было. Понадобились бы только два пакета: один для запроса, а второй для ответа. Впрочем, если учесть возможность передачи сообщений большого размера в обе стороны (например, файла размером в мегабайт), потенциальные ошибки передачи и возможную потерю пакетов, ситуация меняется. Если ответ состоит из сотен пакетов, клиенту необходимо знать, не потерялась ли часть из них при передаче. Как он узнает, что последний полученный пакет был последним отправленным? Или представим, что клиент запросил второй файл. Как он сможет отличить пакет 1 второго файла от потерянного и внезапно найденного пакета 1 из первого файла? Короче говоря, на практике простого протокола запрос/ответ при связи по ненадежной сети обычно недостаточно. В главе 3 мы подробно изучим множество протоколов, позволяющих решить эти и другие проблемы. А пока что отметим только, что надежный упорядоченный байтовый поток между процессами иногда может очень пригодиться.


1.5.5. Службы и протоколы

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

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

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

Илл. 1.31. Соотношение между службой и протоколом

Уместно будет провести аналогию с языками программирования. Служба подобна абстрактному типу данных или объекту в объектно-ориентированном языке. Она описывает, какие операции можно выполнять над объектом, но не уточняет, как они должны быть реализованы. А протокол относится к реализации службы и сам по себе пользователю службы не виден.

Во многих старых протоколах службы и протоколы не различались. В сущности, типичный уровень мог включать примитив службы SEND PACKET10, а пользователь передавал ссылку на полностью готовый пакет. Такое соглашение означало, что все изменения протокола сразу же становились видимы пользователям. Большинство разработчиков сетей считают подобную архитектуру серьезной ошибкой.



9 Дикий кролик (лат.). — Примеч. ред.

10 «Отправить пакет». — Примеч. пер.

Загрузка...