Читать «UNIX: взаимодействие процессов» онлайн - страница 250
Уильям Ричард Стивенс
Дескрипторы передаются через дверь от клиента серверу путем присваивания полю desc_ptr структуры door_arg_t значения указателя на массив структур типа door_desc_t и помещения в поле desc_num количества этих структур. Дескрипторы передаются от сервера клиенту путем присваивания третьему аргументу door_return значения указателя на массив структур door_desc_t и помещения в четвертый аргумент количества передаваемых дескрипторов:
Рис. 15.4. Сервер файлов, передающий клиенту дескриптор
typedef struct door_desc {
door_attr_t d_attributes; /* тег объединения */
union {
struct { /* верна, если tag = DOOR_DESCRIPTOR */
int d_descriptor; /* номер дескриптора */
door_id_t d_id; /* уникальный идентификатор */
} d_desc;
} d_data;
} door_desc_t;
Эта структура содержит объединение (union), и первое поле структуры является тегом, идентифицирующим содержимое этого объединения. В настоящий момент определено только одно поле объединения (структура d_desc, описывающая дескриптор), и тег (d_attributes) должен иметь значение DOOR_DESCRIPTOR.
Пример
Изменим наш пример с сервером файлов таким образом, чтобы сервер открывал файл, передавал дескриптор клиенту, а клиент копировал содержимое файла в стандартный поток вывода. На рис. 15.4 приведена схема приложения. В листинге 15.15 приведен текст программы клиента.
Листинг 15.15. Клиент для сервера, передающего дескриптор
//doors/clientfd1.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 int door, fd;
6 char argbuf[BUFFSIZE], resbuf[BUFFSIZE], buff[BUFFSIZE];
7 size_t len, n;
8 door_arg_t arg;
9 if (argc != 2)
10 err_quit("usage: clientfd1 <server-pathname>");
11 door = Open(argv[1], O_RDWR); /* открываем дверь */
12 Fgets(argbuf, BUFFSIZE, stdin); /* считываем полное имя открываемого файла */
13 len = strlen(argbuf);
14 if (argbuf[len-1] == '\n')
15 len--;
16 /* подготавливаем аргумент и указатель на результат */
17 arg.data_ptr = argbuf; /* аргумент-данные */
18 arg.data_size = len + 1; /* размер данных */
19 arg.desc_ptr = NULL;
20 arg.desc_num = 0;
21 arg.rbuf = resbuf; /* результаты-данные */
22 arg.rsize = BUFFSIZE; /* размер возвращаемых данных */
23 Door_call(door, &arg); /* вызов процедуры сервера */
24 if (arg.data_size != 0)
25 err_quit("%.*s", arg.data_size, arg.data_ptr);
26 else if (arg.desc_ptr == NULL)
27 err_quit("desc_ptr is NULL");
28 else if (arg.desc_num != 1)
29 err_quit("desc_num = %d", arg.desc_num);
30 else if (arg.desc_ptr->d_attributes != DOOR_DESCRIPTOR)
31 err_quit("d_attributes = %d", arg.desc_ptr->d_attributes);
32 fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
33 while((n = Read(fd, buff, BUFFSIZE)) > 0)
34 Write(STDOUT_FILENO, buff, n);
35 exit(0);
36 }
Открываем дверь, считываем полное имя файла
9-15 Имя файла, связанного с дверью, принимается в качестве аргумента командной строки. Имя файла, который должен быть открыт и выведен, считывается из стандартного потока ввода, а завершающий символ перевода строки удаляется.