<p>15.11. Досрочное завершение клиента или сервера</p>

В наших примерах до настоящего момента предполагалось, что в процессе работы клиента и сервера не возникает непредусмотренных ситуаций. Посмотрим, что произойдет, если у клиента или сервера возникнут ошибки. В случае если клиент и сервер являются частями одного процесса (локальный вызов процедуры на рис. 15.1), клиенту не нужно беспокоиться о возникновении ошибок на сервере, и наоборот. Однако если клиент и сервер находятся в различных процессах, нужно учесть возможность досрочного завершения одного из них и предусмотреть способ уведомления второго об этом событии. Об этом нужно заботиться вне зависимости от того, находятся ли клиент и сервер на одном узле или нет.

<p>Досрочное завершение сервера</p>

Если клиент блокируется в вызове door_call, ожидая получения результатов, ему нужно каким-то образом получить уведомление о завершении потока сервера по какой-либо причине. Посмотрим, что происходит в этом случае, прервав работу сервера вызовом pthread_exit. Это приведет к завершению потока сервера (а не всего процесса). В листинге 15.20 приведен текст процедуры сервера.

Листинг 15.20. Процедура сервера, завершающая работу сразу после запуска

//doors/serverintr1.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   pthread_exit(NULL); /* посмотрим, что произойдет с клиентом */

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

9   result = arg * arg;

10  Door_return((char*)result, sizeof(result), NULL, 0);

11 }

Оставшаяся часть сервера не претерпевает изменений по сравнению с листингом 15.2, а программу-клиент мы берем из листинга 15.1.

Запустив клиент, мы увидим, что вызов door_call возвращает ошибку EINTR, если процедура сервера завершается досрочно:

solaris % clientintr1 /tmp/door1 11

door_call error: Interrupted system call

<p>Непрерываемость системного вызова door_call</p>

Документация на door_call предупреждает, что эта функция не предполагает возможности перезапуска (библиотечная функция door_call делает системный вызов с тем же именем). Мы можем убедиться в этом, изменив процедуру сервера таким образом, чтобы она делала паузу в 6 секунд перед возвращением, что показано в листинге 15.21.

Листинг 15.21. Процедура сервера делает паузу в 6 секунд

//doors/serverintr2.с

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   sleep(6); /* клиент получает сигнал SIGCHLD */

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

9   result = arg * arg;

10  Door_return((char*)result, sizeof(result), NULL, 0);

11 }

Изменим теперь клиент из листинга 15.2: установим обработчик сигнала SIGCHLD, добавив порождение процесса и завершение порожденного процесса через 2 секунды. Таким образом, через 2 секунды после вызова door_call дочерний процесс завершит работу, а родительский перехватит сигнал SIGCHLD и произойдет возврат из обработчика сигнала, прерывающий системный вызов door_call. Текст программы-клиента показан в листинге 15.22.

Листинг 15.22. Клиент, перехватывающий сигнал SIGCHLD

//doors/clientintr2.c

1  #include "unpipc.h"

2  void

3  sig_chld(int signo)

4  {

5   return; /* просто прерываем door_call */

6  }

7  int

8  main(int argc, char **argv)

9  {

10  int fd;

11  long ival, oval;

12  door_arg_t arg;

13  if (argc != 3)

14   err_quit("usage: clientintr2 server-pathname integer-value");

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

16  /* подготовка аргументов и указателя на результат */

17  ival = atol(argv[2]);

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

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже