Эффективное программирование TCP-IP

       

Каркас 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   }


Содержание раздела