Каркас UDP-сервера в основном похож на каркас TCP-сервера. Его отличительная особенность - не нужно устанавливать опцию сокета SO_REUSEADDR и обращаться к системным вызовам accept и listen, поскольку UDL - это протокол, не требующий логического соединения (совет 1). Функция main из каркаса [приведена в листинге 2.8.
Листинг 2.8. Функция main из каркаса udpserver.skel
1 int main( int argc, char **argv )
2 {
3 struct sockaddr_in local;
4 char *hname;
5 char *sname;
6 SOCKET s;
7 INIT();
8 if ( argc == 2 )
9 {
10 hname = NULL;
11 sname = argv[ 1 ];
12 }
13 else
14 {
15 hname = argv[ 1 ];
16 sname = argv[ 2 ];
17 }
18 set_address( hname, sname, &local, "udp" );
19 s = socket( AF_INET, SOCK_DGRAM, 0 );
20 if ( !isvalidsock( s ) )
21 error ( 1, errno, "ошибка вызова socket" );
22 if ( bind( s, ( struct sockaddr * ) &local,
23 sizeoff local ) ) )
24 error( 1, errno, "ошибка вызова bind" );
25 server( s, &local );
26 EXIT( 0 ) ;
27 }
udpserver.skel
18 Вызываем функцию set_address для записи в поля переменнойlocal типа sockaddr_in адреса и номера порта, по которому сервер будет принимать датаграммы. Обратите внимание, что вместо "tcp" задается третьим параметром " udp".
19-24 Получаем сокет типа SOCK_DGRAM и привязываем к нему адрес и нон» порта, хранящиеся в переменной local.
25 Вызываем заглушку server, которая будет ожидать входящие датаграммы.
Чтобы получить UDP-версию программы «hello world», следует скопировать каркас в файл udphelloc.с и вместо заглушки вставить следующий код:
static void server( SOCKET s, struct sockaddr_in *localp )
{
struct sockaddr_in peer;
int peerlen;
char buf [ 1 ];
for ( ; ; )
{
peerlen = sizeof( peer );
if ( recvfrom( s, buf, sizeof( buf ), 0,
( struct sockaddr * )&peer, &peerlen ) < 0 )
error( 1, errno, "ошибка вызова recvfrom" );