Шрифт:
for (fd = 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, &testfds)) {
6. Если зафиксирована активность на
server_sockfd
, это может быть запрос на новое соединение, и вы добавляете в множество дескрипторов соответствующий client_sockfd
:
if (fd == server_sockfd) {
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr*)&client_address, &client_len);
FD_SET(client_sockfd, &readfds);
printf("adding client on fd %d\n", client_sockfd);
}
Если активен не сервер, значит, активность проявляет клиент. Если получен
close
, клиент исчезает, и можно удалить его из множества дескрипторов. В противном случае вы "обслуживаете" клиента, как и в предыдущих примерах.
else {
ioctl(fd, FIONREAD, &nread);
if (nread == 0) {
close(fd);
FD_CLR(fd, &readfds);
printf("removing client on fd %d\n", fd);
} else {
read(fd, &ch, 1);
sleep(5);
printf("serving client on fd %d\n", fd);
ch++;
write(fd, &ch, 1);
}
}
}
}
}
}
Примечание
В реальную программу было бы неплохо вставить переменную, содержащую наибольший подключенный номер
fd
(необязательно самый последний подключенный номер fd
). Это помешает просмотру в цикле тысяч номеров fd
, которые даже не подсоединены и потенциально не могут быть готовы к чтению. Мы пропустили этот фрагмент кода для краткости и простоты примера. При запуске этой версии сервера многочисленные клиенты будут обрабатываться последовательно в единственном процессе.
$ ./server5 &
[1] 26686
server waiting
$ ./client3 & ./client3 & ./client3 & ps x
[2] 26689
[3] 26690
adding client on fd 4
server waiting
[4] 26691
PID TTY STAT TIME COMMAND
26686 pts/1 S 0:00 ./server5
26689 pts/1 S 0:00 ./client3
26690 pts/1 S 0:00 ./client3
26691 pts/1 S 0:00 ./client3
26692 pts/1 R+ 0:00 ps x
$ serving client on fd 4
server waiting
adding client on fd 5
server waiting
adding client on fd 6
char from server = В
serving client on fd 5
server waiting
removing client on fd 4
char from server = В
serving client on fd 6
server waiting
removing client on fd 5
server waiting
char from server = В
removing client on fd 6
server waiting
[2] Done ./client3
[3]- Done ./client3
[4]+ Done ./client3
Для полноты аналогии, упомянутой в начале главы, в табл. 15.5 приведены параллели между соединениями на базе сокетов и телефонными переговорами.
Таблица 15.5
Телефон | Сетевые сокеты |
---|---|
Звонок в компанию по номеру 555-0828 | Подключение к IP-адресу 127.0.0.1 |
Ответ на звонок секретаря приемной | Установка соединения с remote host |
Просьба соединить с финансовым отделом. | Маршрутизация с помощью заданного порта (9734) |
Ответ на звонок администратора финансового отдела | Вызов select вернул управление серверу |
Звонок переадресован свободному менеджеру по работе с корпоративными заказчиками | Сервер вызывает accept , создавая новый сокет на добавочный номер 456 |