Литмир - Электронная Библиотека
Содержание  
A
A

sd = socket(format, type, protocol);

Format обозначает домен ("UNIX system" или "Internet"), type — тип связи через гнездо (виртуальный канал или дейтаграмма), а protocol — тип протокола, управляющего взаимодействием. Дескриптор гнезда sd, возвращаемый функцией socket, используется другими системными функциями. Закрытие гнезд выполняет функция close.

Функция bind связывает дескриптор гнезда с именем:

bind(sd, address, length);

где sd — дескриптор гнезда, address — адрес структуры, определяющей идентификатор, характерный для данной комбинации домена и протокола (в функции socket). Length — длина структуры address; без этого параметра ядро не знало бы, какова длина структуры, поскольку для разных доменов и протоколов она может быть различной. Например, для домена "UNIX system" структура содержит имя файла. Процессы-серверы связывают гнезда с именами и объявляют о состоявшемся присвоении имен процессам-клиентам.

С помощью системной функции connect делается запрос на подключение к существующему гнезду:

connect(sd, address, length);

Семантический смысл параметров функции остается прежним (см. функцию bind), но address указывает уже на выходное гнездо, образующее противоположный конец линии связи. Оба гнезда должны использовать одни и те же домен и протокол связи, и тогда ядро удостоверит правильность установки линии связи. Если тип гнезда — дейтаграмма, сообщаемый функцией connect ядру адрес будет использоваться в последующих обращениях к функции send через данное гнездо; в момент вызова никаких соединений не производится.

Пока процесс-сервер готовится к приему связи по виртуальному каналу, ядру следует выстроить поступающие запросы в очередь на обслуживание. Максимальная длина очереди задается с помощью системной функции listen:

listen(sd, qlength)

где sd — дескриптор гнезда, а qlength — максимально-допустимое число запросов, ожидающих обработки.

Архитектура операционной системы UNIX (ЛП) - pic_112.png

Рисунок 11.19. Прием вызова сервером

Системная функция accept принимает запросы на подключение, поступающие на вход процесса-сервера:

nsd = accept(sd, address, addrlen);

где sd — дескриптор гнезда, address — указатель на пользовательский массив, в котором ядро возвращает адрес подключаемого клиента, addrlen — размер пользовательского массива. По завершении выполнения функции ядро записывает в переменную addrlen размер пространства, фактически занятого массивом. Функция возвращает новый дескриптор гнезда (nsd), отличный от дескриптора sd. Процесс-сервер может продолжать слежение за состоянием объявленного гнезда, поддерживая связь с клиентом по отдельному каналу (Рисунок 11.19).

Функции send и recv выполняют передачу данных через подключенное гнездо. Синтаксис вызова функции send:

count = send(sd, msg, length, flags);

где sd — дескриптор гнезда, msg — указатель на посылаемые данные, length размер данных, count — количество фактически переданных байт. Параметр flags может содержать значение SOF_OOB (послать данные out-of-band — "через таможню"), если посылаемые данные не учитываются в общем информационном обмене между взаимодействующими процессами. Программа удаленной регистрации, например, может послать out-of-band сообщение, имитирующее нажатие на клавиатуре терминала клавиши "delete". Синтаксис вызова системной функции recv:

count = recv(sd, buf, length, flags);

где buf — массив для приема данных, length — ожидаемый объем данных, count количество байт, фактически переданных пользовательской программе. Флаги (flags) могут быть установлены таким образом, что поступившее сообщение после чтения и анализа его содержимого не будет удалено из очереди, или настроены на получение данных out-of-band. В дейтаграммных версиях указанных функций, sendto и recvfrom, в качестве дополнительных параметров указываются адреса. После выполнения подключения к гнездам потокового типа процессы могут вместо функций send и recv использовать функции read и write. Таким образом, согласовав тип протокола, серверы могли бы порождать процессы, работающие только с функциями read и write, словно имеют дело с обычными файлами.

Функция shutdown закрывает гнездовую связь:

shutdown(sd, mode)

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

Системная функция getsockname получает имя гнездовой связи, установленной ранее с помощью функции bind:

getsockname(sd, name, length);

Функции getsockopt и setsockopt получают и устанавливают значения различных связанных с гнездом параметров в соответствии с типом домена и протокола.

Рассмотрим обслуживающую программу, представленную на Рисунке 11.20. Процесс создает в домене "UNIX system" гнездо потокового типа и присваивает ему имя sockname. Затем с помощью функции listen устанавливается длина очереди поступающих сообщений и начинается цикл ожидания поступления запросов. Функция accept приостанавливает свое выполнение до тех пор, пока протоколом не будет зарегистрирован запрос на подключение к гнезду с означенным именем; после этого функция завершается, возвращая поступившему запросу новый дескриптор гнезда. Процесс-сервер порождает потомка, через которого будет поддерживаться связь с процессом-клиентом; родитель и потомок при этом закрывают свои дескрипторы, чтобы они не становились помехой для коммуникационного траффика другого процесса. Процесс-потомок ведет разговор с клиентом и завершается после выхода из функции read. Процесс-сервер возвращается к началу цикла и ждет поступления следующего запроса на подключение.

#include ‹sys/types.h›

#include ‹sys/socket.h›

main() {

 int sd, ns;

 char buf[256];

 struct sockaddr sockaddr;

 int fromlen;

 sd = socket(AF_UNIX, SOCK_STREAM, 0);

 /* имя гнезда — не может включать пустой символ */

 bind(sd, "sockname", sizeof("sockname") - 1);

 listen(sd, 1);

 for (;;) {

  ns = accept(sd, &sockaddr, &fromlen);

  if (fork() == 0) { /* потомок */

   close(sd);

   read(ns, buf, sizeof(buf));

   printf("сервер читает %s'\n",buf);

   exit();

  }

128
{"b":"96903","o":1}