Книга: UNIX: разработка сетевых приложений
8.4. Эхо-сервер UDP: функция dg_echo
8.4. Эхо-сервер UDP: функция dg_echo
В листинге 8.2 показана функция dg_echo
.
Листинг 8.2. Функция dg_echo: отражение строк на сокете дейтаграмм
//lib/dg_echo.c
1 #include "unp.h"
2 void
3 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
4 {
5 int n;
6 socklen_t len;
7 char mesg[MAXLINE];
8 for (;;) {
9 len = clilen;
10 n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
11 Sendto(sockfd, mesg, n, 0, pcliaddr, len);
12 }
13 }
Чтение дейтаграммы, отражение отправителю
8-12
Эта функция является простым циклом, в котором очередная дейтаграмма, приходящая на порт сервера, читается функцией recvfrom
и с помощью функции sendto
отправляется обратно.
Несмотря на простоту этой функции, нужно учесть ряд важных деталей. Во- первых, эта функция никогда не завершается. Поскольку UDP — это протокол, не ориентированный на установление соединения, в нем не существует никаких аналогов признака конца файла, используемого в TCP.
Во-вторых, эта функция позволяет создать последовательный сервер, а не параллельный, который мы получали в случае TCP. Поскольку нет вызова функции fork
, один процесс сервера выполняет обработку всех клиентов. В общем случае большинство серверов TCP являются параллельными, а большинство серверов UDP — последовательными.
Для сокета на уровне UDP происходит неявная буферизация дейтаграмм в виде очереди. Действительно, у каждого сокета UDP имеется буфер приема, и каждая дейтаграмма, приходящая на этот сокет, помещается в его буфер приема. Когда процесс вызывает функцию recvfrom
, очередная дейтаграмма из буфера возвращается процессу в порядке FIFO (First In, First Out — первым пришел, первым обслужен). Таким образом, если множество дейтаграмм приходит на сокет до того, как процесс может прочитать данные, уже установленные в очередь для сокета, то приходящие дейтаграммы просто добавляются в буфер приема сокета. Но этот буфер имеет ограниченный размер. Мы обсуждали этот размер и способы его увеличения с помощью параметра сокета SO_RCVBUF
в разделе 7.5.
На рис. 8.3 показано обобщение нашей модели TCP клиент-сервер из главы 5, когда два клиента устанавливают соединения с сервером.
Рис. 8.3. Обобщение модели TCP клиент-сервер с двумя клиентами
Здесь имеется два присоединенных сокета, и каждый из присоединенных сокетов на узле сервера имеет свой собственный буфер приема. На рис. 8.4 показан случай, когда два клиента отправляют дейтаграммы серверу UDP.
Рис. 8.4. Обобщение модели UDP клиент-сервер с двумя клиентами
Существует только один процесс сервера, и у него имеется один сокет, на который сервер получает все приходящие дейтаграммы и с которого отправляет все ответы. У этого сокета имеется буфер приема, в который помещаются все приходящие дейтаграммы.
Функция main
в листинге 8.1 является зависящей от протокола (она создает сокет семейства AF_INET
, а затем выделяет и инициализирует структуру адреса сокета IPv4), но функция dg_echo
от протокола не зависит. Причина, по которой функция dg_echo
не зависит от протокола, заключается в том, что вызывающий процесс (в нашем случае функция main
) должен разместить в памяти структуру адреса сокета корректного размера, и указатель на эту структуру вместе с ее размером передаются в качестве аргументов функции dg_echo
. Функция dg_echo
никогда не углубляется в эту структуру: она просто передает указатель на нее функциям recvfrom
и sendto
. Функция recvfrom
заполняет эту структуру, вписывая в нее IP-адрес и номер порта клиента, и поскольку тот же указатель (pcliaddr
) затем передается функции sendto
в качестве адреса получателя, таким образом дейтаграмма отражается обратно клиенту, отправившему дейтаграмму.
- 8.1. Введение
- 8.2. Функции recvfrom и sendto
- 8.3. Эхо-сервер UDP: функция main
- 8.4. Эхо-сервер UDP: функция dg_echo
- 8.5. Эхо-клиент UDP: функция main
- 8.6. Эхо-клиент UDP: функция dg_cli
- 8.7. Потерянные дейтаграммы
- 8.8. Проверка полученного ответа
- 8.9. Запуск клиента без запуска сервера
- 8.10. Итоговый пример клиент-сервера UDP
- 8.11. Функция connect для UDP
- 8.12. Функция dg_cli (продолжение)
- 8.13. Отсутствие управления потоком в UDP
- 8.14. Определение исходящего интерфейса для UDP
- 8.15. Эхо-сервер TCP и UDP, использующий функцию select
- 8.16. Резюме
- Упражнения
- Запуск InterBase-сервера
- Расширенная установка InterBase-сервера
- Совместимость клиентов и серверов различных версий
- 2.1.3. Функция getopt_long()
- Статистика InterBase-сервера
- Сервер для InterBase
- 1.3.3. Достоинства и недостатки анонимных прокси-серверов
- Минимальный состав сервера InterBase SuperServer
- Отличительные особенности сервера Yaffil
- Группировка по встроенным функциям и UDF
- Встраиваемый сервер
- Использование сервера Yaffil внутри процесса