Каркас UDP-сервера
Каркас 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" );
if ( sendto( s, "hello, world\n", 13, 0,
( struct sockaddr * )&peer, peerlen ) < 0 )
error( 1, errno, "ошибка вызова sendto" );
}
}
Прежде чем тестировать этот сервер, нужно разработать каркас UDP-клиента (листинг 2.10). Но сначала нужно вынести последнюю часть main в библиотечную функцию udp_server:
#include "etcp.h"
SOCKET udp_server( char *host, char *port );
Возвращаемое значение: UDP-сокет, привязанный к хосту host и порту port (в случае ошибки завершает программу).
Как обычно, параметры host и port указывают на строки, содержащие соответственно имя или IP-адрес хоста и имя сервиса либо номер порта в виде ASCII-строки.
Листинг 2.9. Функция udpjserver
1 SOCKET udp_server( char *hname, char *sname )
2 {
3 SOCKET s;
4 struct sockaddr_in local;
5 set_address( hname, sname, &local, "udp" );
6 s = socket( AF_INET, SOCK_DGRAM, 0 );
7 if ( !isvalidsock( s ) )
8 error( 1, errno, "ошибка вызова socket" );
9 if ( bind( s, ( struct sockaddr * ) &local,
10 sizeof( local ) ) )
11 error( 1, errno, "ошибка вызова bind" );
12 return s;
13 }