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.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

R.18.3.4 Приведение указателей на функцию-член

Из книги Справочное руководство по C++ автора Страустрап Бьярн

R.18.3.4 Приведение указателей на функцию-член Указатель на функцию-член некоторого объекта можно привести к указателю на какую-то другую функцию, например (int (*) ())p-›f. Результирующий указатель будет настроен на функцию, вызов которой будет происходить с помощью обращения к


Совет 28. Научитесь использовать функцию base

Из книги Эффективное использование STL автора Мейерс Скотт

Совет 28. Научитесь использовать функцию base При вызове функции base для итератора reverse_iterator будет получен «соответствующий» iterator, однако из сказанного совершенно не ясно, что же при этом происходит. В качестве примера рассмотрим следующий фрагмент, который заносит в вектор


Шаг 25 - Как сделать виртуальной свободную функцию.

Из книги Идиомы и стили С++ автора Makhmutov Albert

Шаг 25 - Как сделать виртуальной свободную функцию. Чаще всего этот прием я видел в отношении оператора operator‹‹. Точнее, не чаще, а всегда. На нем и разберем. Пусть у нас есть иерархия классов, и мы хотим определить диагностическую функцию Dump(). Она должна вываливать


Пример: сервер, использующий порты завершения ввода/вывода

Из книги Системное программирование в среде Windows автора Харт Джонсон М

Пример: сервер, использующий порты завершения ввода/вывода Программа 14.4 представляет видоизмененный вариант программы serverNP (программа 11.3), в котором используются порты завершения ввода/вывода. Этот сервер создает небольшой пул серверных потоков и больший пул


56. Обеспечьте бессбойную функцию обмена

Из книги Стандарты программирования на С++. 101 правило и рекомендация автора Александреску Андрей

56. Обеспечьте бессбойную функцию обмена РезюмеОбычно имеет смысл предоставить для класса функцию swap в целях эффективного и бессбойного обмена внутреннего содержимого объекта с внутренним содержимым другого объекта. Такая функция может пригодиться для реализации ряда


function - Создает новую функцию

Из книги Справочник по Flash автора Коллектив авторов

function - Создает новую функцию functionОпределяет набор операторов, которые вы определили для выполнения определенной задачи. Вы можете декларировать (declare), или определить (define), функцию в том же месте, где вы ее вызываете, или в любом другом месте муви-клипа. При определении


Анализ усилителя с общим эмиттером, использующий упрощенную модель с h-параметрами

Из книги OrCAD PSpice. Анализ электрических цепей автора Кеоун Дж.

Анализ усилителя с общим эмиттером, использующий упрощенную модель с h-параметрами На рис. 3.28 показана упрощенная модель для использования в PSpice, на рис. 3.29 — схема ОЭ, использующая эту модель. Входной файл для анализа приведен далее: Simplified h-Parameter AnalysisVS 1 0 1mVVO 3 0 0VF 4 0 VO 50RS 1 2


Отклик на единичную функцию

Из книги Linux: Полное руководство автора Колисниченко Денис Николаевич

Отклик на единичную функцию Единичная ступенчатая функция показана на рис. 5.20, б. По определению она остается нулевой до t=0, а начиная с этого момента становится равной 1 В. Параметры элементов для схемы, показанной на рис. 5.20, a: R=2 Ом, R1=1 Ом и С=0,125 Ф. Анализ схемы показывает,


16.14. Сервер kHTTPd — веб-сервер уровня ядра

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен

16.14. Сервер kHTTPd — веб-сервер уровня ядра В операционной системе все процессы можно разделить на два типа: процессы уровня ядра и пользовательские процессы. Процесс уровня ядра запускается и работает очень быстро по сравнению с относительно неповоротливым


Операторы SELECT ... INTO

Из книги Искусство программирования на языке сценариев командной оболочки автора Купер Мендель


Раздел Select

Из книги C++ для начинающих автора Липпман Стенли

Раздел Select Но как же система узнает, какой из разделов ControlSetNNN необходимо использовать при обычной загрузке, какой нужно применять при загрузке последней удачной конфигурации, а какой вообще является испорченным? Именно для этих целей и предназначен раздел Select. Он


7.9.1. Тип указателя на функцию

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард

7.9.1. Тип указателя на функцию Как объявить указатель на функцию? Как выглядит формальный параметр, когда фактическим аргументом является такой указатель? Вот определение функции lexicoCompare(), которая сравнивает две строки лексикографически:#include stringint lexicoCompare( const string sl, const


30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept

Из книги автора

30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept Последняя рассматриваемая нами версия сервера устроена следующим образом: главный поток создает пул потоков при запуске сервера, после чего он же вызывает функцию accept и передает