Операционная система UNIX - страница 123

стр.

>listen(sockfd, ...);              Организовать очередь запросов

>for(;;) {

> newsockfd = accept(sockfd, ...); Получить запрос

> if (fork() == 0) {               Породить дочерний процесс

>  close(sockfd);                  Дочерний процесс

>  ...

>  exit(0);

> } else

>  close(newsockfd);               Родительский процесс

>}

В этом сценарии, в то время как дочерний процесс обеспечивает фактический обмен данными с клиентом, родительский процесс продолжает "прослушивать" поступающие запросы, порождая для каждого из них отдельный процесс-обработчик. Очередь позволяет буферизовать запросы на время, пока сервер завершает вызов accept(2) и затем создает дочерний процесс. Заметим, что новый сокет >newsockfd, полученный в результате вызова accept(2), адресует полностью определенный коммуникационный канал: протокол и полные адреса обоих узлов — клиента и сервера. Напротив, для сокета >sockfd определена только локальная часть канала. Это позволяет серверу продолжать использовать >sockfd для "прослушивания" последующих запросов.

Наконец, если для сокетов потока при приеме и передаче данных могут быть использованы стандартные вызовы read(2) и write(2), то сокеты дата- грамм должны пользоваться специальными системными вызовами (эти вызовы также доступны для сокетов других типов):

>#include

>#include


>int send(int s, const char *msg, int len, int flags);

>int sendto(int s, const char *msg, int len, int flags,

> const struct sockaddr* toaddr, int tolen);

>int recv(int s, char *buf, int len, int flags);

>int recvfrom(int s, char *buf, int len, int flags,

> struct sockaddr* fromaddr, int* fromlen);

Функции send(2) и sendto(2) используются для передачи данных удаленному узлу, а функции recv(2) и recvfrom(2) — для их приема. Основным различием между ними является то, что функции send(2) и recv(2) могут быть использованы только для "подсоединенного" сокета, т.е. после вызова connect(2).

Все эти вызовы используют в качестве первого аргумента дескриптор сокета, через который производится обмен данными. Аргумент >msg содержит сообщение длиной >len, которое должно быть передано по адресу >toaddr, длина которого составляет >tolen байтов. Для функции send(2) используется адрес получателя, установленный предшествовавшим вызовом connect(2). Аргумент >buf представляет собой буфер, в который копируются полученные данные.

Параметр >flags может принимать следующие значения:

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

Пример использования сокетов

В заключение приведем пример использования сокетов для организации межпроцессного взаимодействия. Поскольку в данном разделе не затрагиваются сетевые вопросы, то и сокеты, которые будут использованы в примере, принадлежат домену UNIX. Как и в предыдущих примерах, функциональность нашей распределенной системы не отличается разнообразием: клиент посылает серверу сообщение "Здравствуй, Мир!", а сервер отправляет его обратно клиенту, который после получения выводит сообщение на экран.

В примере использованы сокеты датаграмм, которые в домене UNIX практически не отличаются от сокетов потока. В качестве адреса сервера предлагается имя файла ./echo.server (мы полагаем, что в системе запущен только один сервер из данного каталога). Предполагается, что клиенты заранее знают этот адрес. Сервер связывает созданный сокет с этим локальным адресом и таким образом регистрируется в системе. Начиная с этого момента он готов к получению и обработке сообщений. Сервер начинает бесконечный цикл, ожидая сообщений от клиентов, блокируясь на вызове recvfrom(2). При получении сообщения сервер отправляет его обратно, вызывая sendto(2).

Сервер:

>#include

>#include

>#include


>#define MAXBUF 256 char

>buf[MAXBUF];


>main() {

> struct sockaddr_un serv_addr, clnt_addr;

> int sockfd;

> int saddrlen, caddrlen, max caddrlen, n;

> /* Создадим сокет */

> if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0} {

>  printf("Невозможно создать сокет\n");