Читать «UNIX: взаимодействие процессов» онлайн - страница 339

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

6. Вот что мы увидим:

solaris % server6 /tmp/door6

my_thread: created sever thread 4

door_bind error: Bad file number

Запустив сервер 20 раз подряд, мы получим 5 сообщений об ошибке. Предсказать такую ошибку заранее нельзя.

7. Нет. Все, что нужно, — включать возможность отмены каждый раз при вызове процедуры сервера, как мы делали в листинге 15.26. Хотя в этом случае и приходится вызывать pthread_setcancelstate каждый раз при запуске процедуры сервера, накладные расходы, скорее всего, будут невелики.

8. Чтобы проверить это, изменим код одного из серверов (скажем, из листинга 15.6) так, чтобы он вызывал door_revoke из процедуры сервера. Поскольку аргументом door_revoke является дескриптор двери, его придется сделать глобальным. Вот что получится при запуске клиента (из листинга 15.1) два раза подряд:

solaris % client8 /tmp/door8 88

result: 7744

solaris % client8 /tmp/door8 99

door_call error: Bad file number

Первый вызов завершается успешно, что подтверждает наше предположение насчет door_revoke. Второй вызов возвращает ошибку EBADF.

9. Чтобы не делать дескриптор fd глобальным, мы воспользуемся указателем cookiе, который можем передать door_create и который затем будет передаваться процедуре сервера при каждом вызове. В листинге Г.10 приведен текст сервера.

Листинг Г.10. Использование указателя cookie для избавления от глобальных переменных

//doors/server9.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   Door_revoke(*((int *) cookie));

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

9   printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);

10  result = arg * arg;

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

12 }

13 int

14 main(int argc, char **argv)

15 {

16  int fd;

17  if (argc != 2)

18   err_quit("usage: server9 <server-pathname>");

19  fd = Door_create(servproc, &fd, 0);

20  unlink(argv[1]);

21  Close(Open(argv[1], O_CREAT | O_RDWR, FILE MODE));

22  Fattach(fd, argv[1]);

23  for(;;)

24   pause();

25 }

Мы легко могли бы изменить листинги 5.17 и 5.18, поскольку указатель cookie доступен функции my_thread (через структуру door_info_t), которая передает указатель на эту структуру создаваемому потоку (которому нужно знать дескриптор для вызова door_bind).

10. В этом примере атрибуты потока не меняются, поэтому их достаточно инициализировать лишь единожды (в функции main).

Глава 16

1. Программа отображения портов (port mapper) не проверяет серверы на работоспособность во время регистрации. После завершения сервера отображения остаются в силе, в чем мы можем убедиться с помощью пpoгрaммы rpcinfо. Поэтому клиент, связывающийся с программой отображения портов, получит информацию, которая была актуальной до завершения сервера. Когда клиент попытается связаться с сервером по TCP, библиотека RPC получит RST в ответ на пакет SYN (предполагается, что другие процессы не успели подключиться к порту завершенного сервера), что приведет к возврату ошибки функцией clnt_create. Вызов по протоколу UDP будет успешен (поскольку устанавливать соединение не нужно), но при отправке дейтаграмм через устаревший порт ответ получен не будет и функция клиента выйдет по тайм-ауту.