Unix - статьи



         

Демоны - часть 6


Тем, кто читал статью этой серии, посвященную сокетам, должно быть понятно, что здесь происходит. Отметим только одну интересную деталь. Если предыдущий, уже закрытый, сокет, связанный с данным портом, находится в состоянии TIME_WAIT, между закрытием старого и открытием нового сокета может произойти задержка, равная двум периодам жизни сегмента (задержка может составлять до двух минут). Для того, чтобы при повторном запуске демона нам не пришлось ждать, мы используем функцию setsockopt() с параметром SO_REUSEADDR.

Функция AcceptConnections() обрабатывает запросы последовательно, используя блокирующий вызов accept(): int AcceptConnections(const int master) { int proceed = 1, slave, retval = 0; struct sockaddr_in client; socklen_t clilen; while((proceed==1)&&(gGracefulShutdown==0)) { clilen = sizeof(client); slave = accept(master,(struct sockaddr *)&client,&clilen); if(slave

Это не лучший образ поведения демона, но если мы начнем описывать параллельную обработку запросов, редакция не выдержит. Переменная proceed, совместно с переменной gGracefulShutdown, указывает, должна ли программа продолжать обрабатывать запросы. Если очередной вызов connect() или HandleConnection() вернул сообщение об ошибке, этой переменной присваивается 0 и обработка запросов прекращается. Новый сокет, полученный в результате вызовы accept(), передается функции HandleConnection(). int HandleConnection(const int slave) { char readbuf[1025]; size_t bytesRead; const size_t buflen=1024; int retval; retval = ReadLine(slave, readbuf, buflen, &bytesRead); if(retval==0) WriteToSocket(slave, readbuf, bytesRead); return retval; }

Функция HandleConnection() считывает переданную клиентом строку и тут же возвращает ее клиенту. Затем функция AcceptConnections() закрывает соединение, открытое в результате вызова accept(). Функции ReadLine() и WriteToSocket() тривиальны, и рассматривать их мы не будем. Если где-то в цепочке вызовов AcceptConnections(), HandleConnection(), ReadLine() и WriteToSocket() возникла ошибка, информация об ошибке будет передаваться вверх по цепочке до тех пор, пока не достигнет функции main(). В функции main() эта информация приведет к немедленному завершению работы демона с соответствующей записью в журнал системных сообщений.

Рассмотрим, наконец, функцию TidyUp(), к которой обращаются многие функции сервера перед тем, как завершить его работу. void TidyUp(void) { if(gLockFileDesc!=-1) { close(gLockFileDesc); unlink(gLockFilePath); gLockFileDesc=-1; } if(gMasterSocket!=-1) { close(gMasterSocket); gMasterSocket=-1; } }




Содержание  Назад  Вперед