8.15. Эхо-сервер TCP и UDP, использующий функцию select
8.15. Эхо-сервер TCP и UDP, использующий функцию select
Теперь мы объединим наш параллельный эхо-сервер TCP из главы 5 и наш последовательный эхо-сервер UDP из данной главы в один сервер, использующий функцию select для мультиплексирования сокетов TCP и UDP. В листинге 8.14 представлена первая часть этого сервера.
Листинг 8.14. Первая часть эхо-сервера, обрабатывающего сокеты TCP и UDP при помощи функции select
//udpcliserv/udpservselect01.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int listenfd, connfd, udpfd, nready, maxfdp1;
6 char mesg[MAXLINE];
7 pid_t childpid;
8 fd_set rset;
9 ssize_t n;
10 socklen_t len;
11 const int on = 1;
12 struct sockaddr_in cliaddr, servaddr;
13 void sig_chld(int);
14 /* создание прослушиваемого сокета TCP */
15 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
16 bzero(&servaddr, sizeof(servaddr));
17 servaddr.sin_family = AF_INET;
18 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
19 servaddr.sin_port = htons(SERV_PORT);
20 Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
21 Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
22 Listen(listenfd, LISTENQ);
23 /* создание сокета UDP */
24 udpfd = Socket(AF_INET, SOCK_DGRAM, 0);
25 bzero(&servaddr, sizeof(servaddr));
26 servaddr.sin_family = AF_INET;
27 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
28 servaddr.sin_port = htons(SERV_PORT);
29 Bind(udpfd, (SA*)&servaddr, sizeof(servaddr));
Создание прослушиваемого сокета TCP
14-22 Создается прослушиваемый сокет TCP, который связывается с заранее известным портом сервера. Мы устанавливаем параметр сокета SO_REUSEADDR в случае, если на этом порте существуют соединения.
Создание сокета UDP
23-29 Также создается сокет UDP и связывается с тем же портом. Даже если один и тот же порт используется для сокетов TCP и UDP, нет необходимости устанавливать параметр сокета SO_REUSEADDR перед этим вызовом функции bind, поскольку порты TCP не зависят от портов UDP.
В листинге 8.15 показана вторая часть нашего сервера.
Листинг 8.15. Вторая половина эхо-сервера, обрабатывающего TCP и UDP при помощи функции select
udpcliserv/udpservselect01.c
30 Signal(SIGCHLD, sig_chld); /* требуется вызвать waitpid() */
31 FD_ZERO(&rset);
32 maxfdp1 = max(listenfd, udpfd) + 1;
33 for (;;) {
34 FD_SET(listenfd, &rset);
35 FD_SET(udpfd, &rset);
36 if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
37 if (errno == EINTR)
38 continue; /* назад в for() */
39 else
40 err_sys("select error");
41 }
42 if (FD_ISSET(listenfd, &rset)) {
43 len = sizeof(cliaddr);
44 connfd = Accept(listenfd, (SA*)&cliaddr, &len);
45 if ((childpid = Fork()) == 0) { /* дочерний процесс */
46 Close(listenfd); /* закрывается прослушиваемый сокет */
47 str_echo(connfd); /* обработка запроса */
48 exit(0);
49 }
50 Close(connfd); /* родитель закрывает присоединенный сокет */
51 }
52 if (FD_ISSET(udpfd, &rset)) {
53 len = sizeof(cliaddr);
54 n = Recvfrom(udpfd, mesg, MAXLINE, 0, (SA*)&cliaddr, &len);
55 Sendto(udpfd, mesg, n, 0, (SA*)&cliaddr, len);
56 }
57 }
58 }
Установка обработчика сигнала SIGCHLD
30 Для сигнала SIGCHLD устанавливается обработчик, поскольку соединения TCP будут обрабатываться дочерним процессом. Этот обработчик сигнала мы показали в листинге 5.8.
Подготовка к вызову функции select
31-32 Мы инициализируем набор дескрипторов для функции select и вычисляем максимальный из двух дескрипторов, готовности которого будем ожидать.
Вызов функции select
34-41 Мы вызываем функцию select, ожидая только готовности к чтению прослушиваемого сокета TCP или сокета UDP. Поскольку наш обработчик сигнала sig_chld может прервать вызов функции select, обрабатываем ошибку EINTR.
Обработка нового клиентского соединения
42-51 С помощью функции accept мы принимаем новое клиентское соединение, а когда прослушиваемый сокет TCP готов для чтения, с помощью функции fork порождаем дочерний процесс и вызываем нашу функцию str_echo в дочернем процессе. Это та же последовательность действий, которую мы выполняли в главе 5.
Обработка приходящей дейтаграммы
52-57 Если сокет UDP готов для чтения, дейтаграмма пришла. Мы читаем ее с помощью функции recvfrom и отправляем обратно клиенту с помощью функции sendto.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
Пример: сервер, использующий порты завершения ввода/вывода
Пример: сервер, использующий порты завершения ввода/вывода Программа 14.4 представляет видоизмененный вариант программы serverNP (программа 11.3), в котором используются порты завершения ввода/вывода. Этот сервер создает небольшой пул серверных потоков и больший пул
function - Создает новую функцию
function - Создает новую функцию functionОпределяет набор операторов, которые вы определили для выполнения определенной задачи. Вы можете декларировать (declare), или определить (define), функцию в том же месте, где вы ее вызываете, или в любом другом месте муви-клипа. При определении
30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept
30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept Последняя рассматриваемая нами версия сервера устроена следующим образом: главный поток создает пул потоков при запуске сервера, после чего он же вызывает функцию accept и передает
16.14. Сервер kHTTPd — веб-сервер уровня ядра
16.14. Сервер kHTTPd — веб-сервер уровня ядра В операционной системе все процессы можно разделить на два типа: процессы уровня ядра и пользовательские процессы. Процесс уровня ядра запускается и работает очень быстро по сравнению с относительно неповоротливым
Раздел Select
Раздел Select Но как же система узнает, какой из разделов ControlSetNNN необходимо использовать при обычной загрузке, какой нужно применять при загрузке последней удачной конфигурации, а какой вообще является испорченным? Именно для этих целей и предназначен раздел Select. Он
Анализ усилителя с общим эмиттером, использующий упрощенную модель с h-параметрами
Анализ усилителя с общим эмиттером, использующий упрощенную модель с h-параметрами На рис. 3.28 показана упрощенная модель для использования в PSpice, на рис. 3.29 — схема ОЭ, использующая эту модель. Входной файл для анализа приведен далее: Simplified h-Parameter AnalysisVS 1 0 1mVVO 3 0 0VF 4 0 VO 50RS 1 2
Отклик на единичную функцию
Отклик на единичную функцию Единичная ступенчатая функция показана на рис. 5.20, б. По определению она остается нулевой до t=0, а начиная с этого момента становится равной 1 В. Параметры элементов для схемы, показанной на рис. 5.20, a: R=2 Ом, R1=1 Ом и С=0,125 Ф. Анализ схемы показывает,
R.18.3.4 Приведение указателей на функцию-член
R.18.3.4 Приведение указателей на функцию-член Указатель на функцию-член некоторого объекта можно привести к указателю на какую-то другую функцию, например (int (*) ())p-›f. Результирующий указатель будет настроен на функцию, вызов которой будет происходить с помощью обращения к
56. Обеспечьте бессбойную функцию обмена
56. Обеспечьте бессбойную функцию обмена РезюмеОбычно имеет смысл предоставить для класса функцию swap в целях эффективного и бессбойного обмена внутреннего содержимого объекта с внутренним содержимым другого объекта. Такая функция может пригодиться для реализации ряда
Шаг 25 - Как сделать виртуальной свободную функцию.
Шаг 25 - Как сделать виртуальной свободную функцию. Чаще всего этот прием я видел в отношении оператора operator‹‹. Точнее, не чаще, а всегда. На нем и разберем. Пусть у нас есть иерархия классов, и мы хотим определить диагностическую функцию Dump(). Она должна вываливать
Совет 28. Научитесь использовать функцию base
Совет 28. Научитесь использовать функцию base При вызове функции base для итератора reverse_iterator будет получен «соответствующий» iterator, однако из сказанного совершенно не ясно, что же при этом происходит. В качестве примера рассмотрим следующий фрагмент, который заносит в вектор
7.9.1. Тип указателя на функцию
7.9.1. Тип указателя на функцию Как объявить указатель на функцию? Как выглядит формальный параметр, когда фактическим аргументом является такой указатель? Вот определение функции lexicoCompare(), которая сравнивает две строки лексикографически:#include stringint lexicoCompare( const string sl, const