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

ЖАНРЫ

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

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

Шрифт:

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 Имя файла, связанного с дверью, принимается в качестве аргумента командной строки. Имя файла, который должен быть открыт и выведен, считывается из стандартного потока ввода, а завершающий символ перевода строки удаляется.

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

16-22 Подготавливается структура door_arg_t. К размеру имени файла мы добавляем единицу, чтобы сервер мог дополнить его завершающим нулем.

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

23-31 Мы вызываем процедуру сервера и проверяем результат. Должен возвращаться только один дескриптор и никаких данных. Вскоре мы увидим, что сервер возвращает данные (сообщение об ошибке) только в том случае, если он не может открыть файл. В этом случае функция err_quit выводит сообщение об ошибке.

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

32-34 Дескриптор извлекается из структуры door_desc_t, и файл копируется в стандартный поток вывода.

В листинге 15.16 приведен текст процедуры сервера. Функция main по сравнению с листингом 15.3 не изменилась.

Листинг 15.16. Процедура сервера, открывающая файл и возвращающая клиенту дескриптор

//doors/serverfd1.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 int fd;

7 char resbuf[BUFFSIZE];

8 door_desc_t desc;

9 dataptr[datasize-1] = 0; /* завершающий О */

10 if ((fd = open(dataptr, O_RDONLY)) == –1) {

11 /* ошибка, нужно сообщить клиенту */

12 snprintf(resbuf, BUFFSIZE, "%s: can't open, %s",

13 dataptr, strerror(errno));

14 Door_return(resbuf, strlen(resbuf), NULL, 0);

15 } else {

16 /* ОК, возвращаем дескриптор */

17 desc.d_data.d_desc.d_descriptor = fd;

18 desc.d_attributes = DOOR_DESCRIPTOR;

19 Door_return(NULL, 0, &desc, 1);

20 }

21 }

Открытие файла для клиента

9-14 Мы завершаем полное имя файла клиента нулем и делаем попытку открыть этот файл вызовом open. Если возникает ошибка, сообщение о ней возвращается клиенту.

Успешное открытие файла

15-20 Если файл был успешно открыт, клиенту возвращается только его дескриптор.

Запустим сервер и укажем ему имя двери /tmp/fd1, а затем запустим клиент:

solaris % clientfd1 /tmp/fd1

/etc/shadow

/etc/shadow: can't open. Permission denied

solaris % clientfd1 /tmp/fd1

/no/such/file

/no/such/file: can't open. No such file or directory

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