Тот факт, что исходный сокет все еще доступен, и что сокеты ведут себя как файловые дескрипторы, дает нам метод одновременного обслуживания многих клиентов. Если сервер вызовет функцию
fork
для создания своей второй копии, открытый сокет будет унаследован новым дочерним процессом. Далее он сможет обмениваться данными с подключившимся клиентом, в то время как основной сервер продолжит прием последующих запросов на соединение. В действительности в вашу программу сервера нужно внести очень простое изменение, показанное в упражнении 15.7.
Поскольку вы создаете дочерние процессы, но
не ждете их завершения, следует сделать так, чтобы сервер игнорировал сигналы
SIGCHLD
, препятствуя возникновению процессов-зомби.
Упражнение 15.7. Сервер для многочисленных клиентов
1. Программа server4.c начинается так же, как последний рассмотренный сервер с важным добавлением директивы
include
для заголовочного файла signal.h. Переменные и процедуры создания и именования сокета остались прежними:
2. Создайте очередь соединений, игнорируйте подробности завершения дочернего процесса и ждите запросов клиентов:
listen(server_sockfd, 5);
signal(SIGCHLD, SIG_IGN);
while(1) {
char ch;
printf("server waiting\n");
3. Примите запрос на соединение:
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct_sockaddr*)&client_address, &client_len);
4. Вызовите
fork
с целью
создания процесса для данного клиента и выполните проверку, чтобы определить, родитель вы или потомок:
if (fork == 0) {
5. Если вы потомок, то можете читать/писать в программе-клиенте на сокете
client_sockfd
. Пятисекундная задержка нужна для того, чтобы это продемонстрировать:
read(client_sockfd, &ch, 1);
sleep(5);
ch++;
write(client_sockfd, &ch, 1);
close(client_sockfd);
exit(0);
}
6. В противном случае вы должны быть родителем и ваша работа с данным клиентом закончена:
else {
close(client_socket);
}
}
}
Код включает пятисекундную задержку при обработке запроса клиента для имитации вычислений сервера или обращения к базе данных. Если бы вы проделали это в предыдущем сервере, каждое выполнение программы client3 заняло бы пять секунд. С новым сервером вы сможете обрабатывать множественные клиентские программы client3 параллельно с общим затраченным временем, чуть превышающим пять секунд.