Поскольку в протоколе UDP соединения не устанавливаются (совет 1), inetd нечего слушать. При этом inetd запрашивает операционную систему (с помощью вызова select) о приходе новых датаграмм в порт UDP-сервера. Получив извещение, inetd дублирует дескриптор сокета на stdin, stdout и stderr и запускает UDP-сервер. В отличие от работы с TCP-серверами при наличии флага nowait, inetd больше не предпринимает с этим портом никаких действий, пока сервер не завершит сеанс. В этот момент он снова предлагает системе извещать его о новых датаграммах. Прежде чем закончить работу, серверу нужно прочесть хотя бы одну датаграмму из сокета, чтобы inetd не «увидел» то же самое сообщение, что и раньше. В противном случае он опять запустит сервер, войдя в бесконечный цикл.
Пример простого UDP-сервера, запускаемого через inetd, приведен в листинге 3.4. Этот сервер возвращает то, что получил, добавляя идентификатор своего процесса.
Листинг 3.4. Простой сервер, реализующий протокол запрос-ответ
udpecho1.с
1 ttinclude "etcp.h"
2 int main( int argc, char **argv )
3 {
4 struct sockaddr_in peer;
5 int rc;
6 int len;
7 int pidsz;
8 char buf[ 120 ] ;
9 pidsz = sprintf( buf, "%d: ", getpid () ) ;
10 len = sizeof( peer );
11 rc = recvfromt 0, buf + pidsz, sizeof( buf ) - pidsz, 0,
12 ( struct sockaddr * )&peer, &len);
13 if ( rc <= 0 )
14 exit ( 1 ) ;
15 sendto( 1, buf, re + pidsz, 0,
16 (struct sockaddr * )&peer, len);
17 exit( 0 );
18 }
updecho1
9 Получаем идентификатор процесса сервера (PID) от операционной системы, преобразуем его в код ASCII и помещаем в начало буфера ввода/вывода.
10-14 Читаем датаграмму от клиента и размещаем ее в буфере после идентификатора процесса. 15-17 Возвращаем клиенту ответ и завершаем сеанс.
Для экспериментов с этим сервером воспользуемся простым клиентом, код которого приведен в листинге 3.5. Он читает запросы из стандартного ввода, отсылает их серверу и печатает ответы на стандартном выводе.