Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

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

Шрифт:

30.7. Сервер TCP с предварительным порождением процессов и защитой вызова accept блокировкой файла

Описанная выше реализация, позволяющая нескольким процессам вызывать функцию

accept
на одном и том же прослушиваемом дескрипторе, возможна только для систем 4.4BSD, в которых функция
accept
реализована внутри ядра. Ядра системы SVR4, в которых accept реализована как библиотечная функция, не допускают этого. В самом деле, если мы запустим сервер из предыдущего раздела, в котором имеется несколько дочерних процессов, в Solaris 2.5 (система SVR4), то вскоре после того, как клиенты начнут соединяться с сервером, вызов функции
accept
в одном из дочерних процессов вызовет ошибку
EPROTO
, что свидетельствует об ошибке протокола.

ПРИМЕЧАНИЕ

Причины возникновения этой проблемы с библиотечной версией функции accept в SVR4 связаны с реализацией потоков STREAMS и тем фактом, что библиотечная функция accept не является атомарной операцией. В Solaris 2.6 эта проблема решена, но в большинстве реализаций SVR4 она остается.

Решением этой проблемы является защита вызова функции

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

Существует несколько способов реализации защиты вызова функции

accept
, о которых рассказывается во втором томе [2] данной серии. В этом разделе мы используем блокировку файла функцией
fcntl
согласно стандарту POSIX.

Единственным изменением в функции

main
(см. листинг 30.6) будет добавление вызова функции
my_lock_init
перед началом цикла, в котором создаются дочерние процессы:

+ my_lock_init("/tmp/lock.XXXXXX"); /* один файл для всех дочерних

2

Стивенс У. UNIX: взаимодействие процессов. — СПб.: Питер, 2002.

процессов */

for (i = 0; i < nchildren; i++)

pids[i] = child_make(i, listenfd, addrlen); /* возвращение

родительского процесса */

Функция

child_make
остается такой же, как в листинге 30.8. Единственным изменением функции
child_main
(см. листинг 30.9) является блокирование перед вызовом функции
accept
и снятие блокировки после завершения этой функции:

for (;;) {

clilen = addrlen;

+ my_lock_wait;

connfd = Accept(listenfd, cliaddr, &clilen);

+ my_lock_release;

web_child(connfd); /* обработка запроса */

Close(connfd);

}

В листинге 30.12 показана наша функция

my_lock_init
, в которой используется блокировка файла согласно стандарту POSIX.

Листинг 30.12. Функция my_lock_init: блокировка файла

//server/lock_fcntl.c

1 #include "unp.h"

2 static struct flock lock_it, unlock_it;

3 static int lock_fd = -1;

4 /* fcntl не выполнится, если не будет вызвана функция my_lock_init */

5 void

6 my_lock_init(char *pathname)

7 {

8 char lock_file[1024];

9 /* копируем строку вызывающего процесса на случай, если это константа */

10 strncpy(lock_file, pathname, sizeof(lock_file));

11 lock_fd = Mkstemp(lock_file);

12 Unlink(lock_file); /* но lock_fd остается открытым */

13 lock_it.l_type = F_WRLCK;

14 lock_it.l_whence = SEEK_SET;

15 lock_it.l_start = 0;

16 lock_it.l_len = 0;

17 unlock_it.l_type = F_UNLCK;

  • Читать дальше
  • 1
  • ...
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: