Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 [ 127 ] 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

Этот подход не работает. Дескрипторы вычисляются для каждого процесса в отдельности. Предположим, что значение дескриптора файла на сервере равно 4. Даже если дескриптор с тем же значением и открыт клиентом, он почти наверняка относится к другому файлу. Единственная ситуация, в которой дескрипторы одного процесса имеют значение для другого процесса, возникает при вызове fork.

Если первый свободный дескриптор сервера имеет значение 4, вызов open вернет именно это значение. Если сервер передает дескриптор 4 клиенту, а у клиента наименьшее свободное значение дескриптора равно 7, нужно, чтобы дескриптор 7 клиента был установлен в соответствие с тем же файлом, что и дескриптор 4 сервера. Рисунки 15.4 в [21 ] и 18.4 в [23] иллюстрируют, что должно произойти с точки зрения ядра: два дескриптора (4 у сервера и 7 у клиента) должны указывать на один и тот же файл из таблицы ядра. Интерфейсы типа дверей и доменных сокетов Unix скрывают внутренние детали реализации, предоставляя процессам возможность легко передавать дескрипторы друг другу.

Дескрипторы передаются через дверь от клиента серверу путем присваивания полю clesc ptr структуры door arg t значения указателя на массив структур типа door desc t и помещения в поле desc num количества этих структур. Дескрипторы передаются от сервера клиенту путем присваивания третьему аргументу door return значения указателя на массив структур door desc t и помещения в четвертый аргумент количества передаваемых дескрипторов:

сервер

main { ) {


door call (servfd,

filefd = arg.desc ptr-> ... while {(n = Read (filefd, )) > 0) Write (STDOUT FILENO,);

servproc ( )

door desc t desc;

V ...

fd = open ( ); desc... = fd

door return (NULL, 0, &desc, 1);

fd = door create ( ); fattach (fd, path);

Рис. 15.4. Сервер файлов, передающий клиенту дескриптор

typedef struct door desc { door attr t d attributes: union { struct {

int d descriptor; door id t d id:

/* тег объединения */

/* верна, если tag = DOOR DESCRIPTOR */

/* номер дескриптора */

/* уникальный идентификатор */



} d desc; } d data: } door desc t:

Эта структура содержит объединение (union), и первое поле структуры является тегом, идентифицирующим содержимое этого объединения. В настоящий момент определено только одно поле объединения (структура ddesc, описывающая дескриптор), и тег (d attributes) должен иметь значение DOOR DESCRIPTOR.

Пример

Изменим нащ пример с сервером файлов таким образом, чтобы сервер открывал файл, передавал дескриптор клиенту, а клиент копировал содержимое файла в стандартный поток вывода. На рис. 15.4 приведена схема приложения. В листинге 15.15 приведен текст программы клиента.

Листинг 15.15. Клиент для сервера, передающего дескриптор

doors/clientfdl.c

1 finclude unpipc.h

2 int

3 mainCint argc, char **argv)

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; clientfdl <server-pathname> ):

11 door = Open(argv[l]. 0 RDWR); /* открываем дверь */

12 FgetsCargbuf. BUFFSIZE, stdin): /* считываем полное имя открываемого файла */

13 len = strlen(argbuf):

14 if (argbuf[len-l] - Чп)

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 = Xd . arg.desc num):

30 else if (arg.desc ptr->d attributes != DOOR DESCRIPTOR)

31 err quit( d attributes = Xd . arg.desc ptr->d attributes):

32 fd = arg.desc ptr->d data.d desc.d descriptor; продолжение



Листинг 15.15 (продолжение)

33 while ( (п = ReadCfd, buff, BUFFSIZE)) > 0)

34 Write(STDOUT FILENO, buff, n);

35 exitCO);

36 }

Открываем дверь, считываем полное имя файла

9-15 Имя файла, связанного с дверью, принимается в качестве аргумента командной строки. Имя файла, который должен быть открыт и выведен, считывается из стандартного потока ввода, а завершающий символ перевода строки удаляется.

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

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

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

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

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

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

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

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

doors/serverfdl.c

1 finclude unpipc.h

2 void

3 servprocCvoid *cookie, char *dataptr, size t datasize,

4 door desc t *descptr, size t ndesc)

6 int fd;

7 char resbuf[BUFFSIZE];

8 door desc t desc;

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

10 if С Cfd = openCdataptr, 0 RDONLY)) == -1) {

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

12 snprintfСresbuf, BUFFSIZE, Xs: cant open, Xs .

13 dataptr, strerrorCerrno));

14 Door returnCresbuf. strlenCresbuf). NULL. 0);

15 } else f



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 [ 127 ] 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.