# killall -HUP inetd
Существует много параметров, которые можно применять для управления поведением соединений на базе сокетов — слишком много для подробного описания в этой главе. Для манипулирования параметрами используют функцию setsockopt:
#include
int setsockopt(int socket, int level, int option_name,
const void *option value, size_t option len);
Задавать параметры можно на разных уровнях иерархии протоколов. Для установки параметров на уровне сокета вы должны задать levelравным SOL_SOCKET. Для задания параметров на более низком уровне протоколов (TCP, UDP и т.д.) приравняйте параметр level номеру протокола (полученному либо из заголовочного файла netinet/in.h, либо из функции getprotobyname).
В аргументе option_nameуказывается имя задаваемого параметра, аргумент option_valueсодержит произвольное значение длиной option_lenбайтов, передаваемое без изменений обработчику низкоуровневого протокола.
Параметры уровня сокета определены в заголовочном файле sys/socket.h и включают приведенные в табл. 15.4 значения.
Таблица 15.5
| Параметр |
Описание |
SO_DEBUG |
Включает отладочную информацию |
SO_KEEPALIVE |
Сохраняет активными соединения при периодических передачах |
SO_LINGER |
Завершает передачу перед закрытием |
Параметры SO_DEBUGи SO_KEEPALIVEпринимают целое значение option_valueдля установки или включения (1) и сброса или выключения (0). Для параметра SO_LINGERнужна структура типа linger, определенная в файле sys/socket.h и задающая состояние параметра и величину интервала задержки.
Функция setsockoptвозвращает 0 в случае успеха и -1 в противном случае. На страницах интерактивного справочного руководства описаны дополнительные параметры и ошибки.
До сих пор в этой главе вы видели, как применяются сокеты для реализации клиент-серверных систем, как локальных, так действующих, в сети. После установки соединения на базе сокетов они ведут себя как низкоуровневые открытые файловые дескрипторы и во многом как двунаправленные каналы.
Теперь необходимо рассмотреть случай множественных клиентов, одновременно подключающихся к серверу. Вы видели, что, когда серверная программа принимает от клиента запрос на соединение, создается новый сокет, а исходный сокет, ожидающий запросы на соединение, остается доступен для последующих запросов. Если сервер не сможет немедленно принять поступившие позже запросы на соединения, они сохранятся в очереди ожидания.
Тот факт, что исходный сокет все еще доступен, и что сокеты ведут себя как файловые дескрипторы, дает нам метод одновременного обслуживания многих клиентов. Если сервер вызовет функцию forkдля создания своей второй копии, открытый сокет будет унаследован новым дочерним процессом. Далее он сможет обмениваться данными с подключившимся клиентом, в то время как основной сервер продолжит прием последующих запросов на соединение. В действительности в вашу программу сервера нужно внести очень простое изменение, показанное в упражнении 15.7.
Поскольку вы создаете дочерние процессы, но не ждете их завершения, следует сделать так, чтобы сервер игнорировал сигналы SIGCHLD, препятствуя возникновению процессов-зомби.
Упражнение 15.7. Сервер для многочисленных клиентов
1. Программа server4.c начинается так же, как последний рассмотренный сервер с важным добавлением директивы includeдля заголовочного файла signal.h. Переменные и процедуры создания и именования сокета остались прежними:
#include
#include
#include
#include
#include
#include
#include
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
2. Создайте очередь соединений, игнорируйте подробности завершения дочернего процесса и ждите запросов клиентов:
listen(server_sockfd, 5);
signal(SIGCHLD, SIG_IGN);
while(1) {
char ch;
printf("server waiting\n");
3. Примите запрос на соединение:
client_len = sizeof(client_address);
Читать дальше