Чтение онлайн

ЖАНРЫ

UNIX: взаимодействие процессов

Стивенс Уильям Ричард

Шрифт:

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

Пример

Начнем описание интерфейса дверей с простого примера: клиент передает серверу длинное целое, а сервер возвращает клиенту квадрат этого значения тоже как длинное целое. В листинге 15.1 [1]

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

1

Все исходные тексты, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com/download.

Листинг 15.1 .Клиент передает серверу длинное целое для возведения его в квадрат

//doors/client1.c

1 #include "unpipc.h"

2 int

3 main(int argc, char **argv)

4 {

5 int fd;

6 long ival, oval;

7 door_arg_t arg;

8 if (argc != 3)

9 err_quit("usage: client1 <server-pathname> <integer-value>");

10 fd = Open(argv[1], O_RDWR); /* открываем дверь */

11 /* задаем аргументы и указатель на результат */

12 ival = atol(argv[2]);

13 arg.data_ptr = (char *) &ival; /* аргументы */

14 arg.data_size = sizeof(long); /* размер аргументов */

15 arg.desc_ptr = NULL;

16 arg.desc_num = 0;

17 arg.rbuf = (char *) &oval; /* результат */

18 arg.rsize = sizeof(long); /* размер результата */

19 /* вызываем процедуру на сервере и выводим результат */

20 Door_call(fd, &arg);

21 printf("result: %ld\n", oval);

22 exit(0);

23 }

Открываем дверь

8-10 Дверь задается полным именем, передаваемым в качестве аргумента командной строки. Она открывается вызовом open. Возвращаемый дескриптор называется дескриптором двери, но часто его самого и называют дверью.

Подготовка аргументов и указателя на результат

11-18 Структура arg содержит указатели на аргументы и результат. Поле data_ptr указывает на первый байт аргументов, a data_size содержит количество байтов в аргументах. Два поля desc_ptr и desc_num предназначены для передачи дескрипторов, о чем мы будем подробно говорить в разделе 15.8. rbuf указывает на первый байт буфера результата, a rsize задает его размер.

Вызов процедуры на сервере и вывод результата

19-21 Мы вызываем процедуру на сервере с помощью door_call; аргументами этого вызова являются дескриптор двери и указатель на структуру аргументов. После возвращения из этого вызова программа печатает получившийся результат.

Программа-сервер

приведена в листинге 15.2. Она состоит из процедуры сервера с именем servproc и функции main.

Листинг 15.2. Сервер, возводящий длинное целое в квадрат

//doors/server1.c

1 #include "unpipc.h"

2 void

3 servproc(void *cookie, char *dataptr, size_t datasize,

4 door_desc_t *descptr, size_t ndesc)

5 {

6 long arg, result;

7 arg = *((long *) dataptr);

8 result = arg * arg;

9 Door_return((char *) &result, sizeof(result), NULL, 0);

10 }

11 int

12 main(int argc, char **argv)

13 {

14 int fd;

15 if (argc != 2)

16 err_quit("usage: server1 <server-pathname>");

17 /* создание двери и связывание ее с файлом */

18 fd = Door_create(servproc, NULL, 0);

19 unlink(argv[1]);

20 Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));

21 Fattach(fd, argv[1]);

22 /* функция servproc обрабатывает все запросы клиентов */

23 for (;;)

24 pause;

25 }

Процедура сервера

2-10 Процедура сервера вызывается с пятью аргументами, но мы используем только один из них — dataptr. Он указывает на первый байт аргумента. Аргумент, представляющий собой длинное целое, передается через этот указатель и возводится в квадрат. Управление передается клиенту вместе с результатом вызовом door_return. Первый аргумент указывает на результат, второй задает его размер, а оставшиеся предназначены для возврата дескрипторов.

Создание дескриптора двери и связывание с ним файла

17-21 Дескриптор двери создается вызовом door_create. Первый аргумент является указателем на функцию, соответствующую этой двери (servproc). После получения этого дескриптора его нужно связать с некоторым именем в файловой системе, поскольку оно будет использоваться клиентом для подключения к этой двери. Делается это путем создания обычного файла в файловой системе (сначала мы вызываем unlink, на тот случай, если такой файл уже существует, причём возможная ошибка игнорируется) и вызова fattach — функции SVR4, связывающей дескриптор с полным именем файла.

Главный поток сервера ничего не делает

22-24 Главный поток сервера блокируется при вызове pause. Вся функциональность обеспечивается функцией servproc, которая будет запускаться как отдельный поток каждый раз при получении запроса клиента.

Запустим сервер в отдельном окне:

solaris % server1 /tmp/server1

После этого запустим пpoгрaммy-клиeнт в другом окне, указав в качестве аргумента то же полное имя, которое было указано при вызове сервера:

Поделиться с друзьями: