1.3.4. Примитивы служб
Служба (сервис) формально описывается набором примитивов или операций, доступных пользователю или другому объекту для получения сервиса. Эти примитивы заставляют службу выполнять некоторые действия или служат ответами на действия объекта того же уровня. Если набор протоколов входит в состав операционной системы (как часто и бывает), то примитивы являются системными вызовами. Они приводят к возникновению системных прерываний в привилегированном режиме, в результате чего управление машиной передается операционной системе, которая и отсылает нужные пакеты.
Набор доступных примитивов зависит от природы сервиса. Скажем, примитивы сервисов с установлением соединения и без него различаются. В табл. 1.3 приведен минимальный набор примитивов, обеспечивающий надежную передачу битового потока
в среде типа «клиент-сервер». Они будут знакомы поклонникам сокет-интерфейса Беркли, поскольку примитивы — упрощенная версия этого интерфейса.
Таблица 1.3. Шесть сервисных примитивов, обеспечивающих простую передачу с установлением соединения
Примитив
Значение
LISTEN (ожидание) CONNECT (соединение) ACCEPT (прием) RECEIVE (прием)
SEND (отправка) DISCONNECT (разрыв)
Блокировка, ожидание входящего соединения
Установка соединения с ожидающим объектом того же ранга
Прием входящего соединения от объекта того же ранга
Блокировка, ожидание входящего сообщения
Отправка сообщения ожидающему объекту того же ранга
Разрыв соединения
Эти примитивы могут использоваться для взаимодействия запрос-ответ в среде клиент-сервер. Чтобы проиллюстрировать, как это происходит, мы покажем набросок простого протокола, который осуществляет службу, используя общепризнанные дейтаграммы.
Вначале сервер исполняет LISTEN, показывая тем самым, что он готов устанавливать входящие соединения. Этот примитив обычно реализуется в виде блокирующего системного вызова. После его исполнения процесс сервера приостанавливается до тех пор, пока не будет установлено соединение.
Затем процесс клиента выполняет примитив CONNECT, устанавливая соединение с сервером. В системном вызове должно быть указано, с кем именно необходимо установить связь. Для этого может вводиться специальный параметр, содержащий адрес сервера. Далее операционная система клиента посылает равноранговой сущности пакет с запросом на соединение, как показано на рис. 1.15 стрелочкой с пометкой (1). Процесс клиента приостанавливается в ожидании ответа.
Когда пакет приходит на сервер, операционная система обнаруживает запрос на соединение. Она проверяет, есть ли слушатель, и в этом случае разблокирует его. Затем процесс сервера может установить соединение с помощью ACCEPT. Он посылает ответ (2) назад к процессу клиента, чтобы принять соединение. Прибытие этого ответа освобождает клиента. Начиная с этого момента считается, что сервер и клиент установили соединение.
Самым очевидным жизненным примером такого взаимодействия может служить звонок покупателя (клиента) в сервисный центр компании. Менеджер сервисного центра должен находиться у телефона, чтобы иметь возможность ответить на звонок. Клиент совершает звонок. Когда менеджер поднимает трубку, считается, что соединение установлено.
Следующим шагом будет выполнение сервером примитива RECEIVE, подготавливающего систему к принятию первого запроса. В нормальной ситуации это происходит сразу же после прекращения ожидания (LISTEN), даже до того, как клиент получает подтверждение соединения. Системный вызов RECEIVE вновь блокирует сервер.
Рис. 1.15. Простейшее взаимодействие клиента и сервера с использованием общепризнанных дейтаграмм
Клиент выполняет SEND, передает запрос (3) и сразу же выполняет RECEIVE, ожидая ответ. Прием пакета с запросом разблокирует сервер, благодаря чему он может обработать запрос. По окончании обработки сервер выполняет примитив SEND, и ответ отсылается клиенту (4). Прием пакета разблокирует клиента, теперь наступает его очередь обрабатывать пакет. Если у клиента есть еще запросы к серверу, он может отослать их.
Когда запросы клиента окончены, он осуществляет разрыв соединения с помощью DISCONNECT. Обычно первый примитив DISCONNECT отсылает пакет, уведомляющий сервер об окончании сеанса, и блокирует клиента (5). В ответ сервер генерирует свой примитив DISCONNECT, являющийся подтверждением для клиента и командой, разрывающей связь. Клиент, получив его, разблокируется, и соединение считается окончательно разорванным. Именно так в двух словах можно описать схему коммуникации с установлением соединения.