Каркас UDP-клиента
Функция main в каркасе UDP-клиента выполняет в основном запись в поля переменной peer указанных адреса и номера порта сервера и получает сокет типа SOCK_DGRAM. Она показана в листинге 2.10. Весь остальной код каркаса такой же, как для .
Листинг 2.10. Функция main из каркаса udpclient.skel
1 int main( int argc, char **argv )
2 {
3 struct sockaddr_in peer;
4 SOCKET s;
5 INIT();
6 set_address( argv[ 1 ], argv[ 2 ], &peer, "udp" );
7 s = socket( AF_INET, SOCK_DGRAM, 0 );
8 if ( !isvalidsock( s ) )
9 error( 1, errno, "ошибка вызова socket" ) ;
10 client( s, &peer ) ;
11 exit( 0 ) :
12 }
Теперь можно протестировать одновременно этот каркас и программу udphello, для чего необходимо скопировать udpclient.skel в файл udphelloc.с и вместо клиентской заглушки подставить такой код:
static void client( SOCKET s, struct sockaddr_in *peerp )
{
int rc;
int peerlen;
char buff [ 120 ];
peerlen = sizeof( *peerp );
if ( sendto( s, "", 1, 0, ( struct sockaddr * )peerp,
peerlen ) < 0 )
error( 1, errno, "ошибка вызова sendto" );
rc= recvfrom( s, buf, sizeof( buf ), 0,
( struct sockaddr * )peerp, &peerlen );
if ( rc >= 0 )
write ( 1, buf, rc );
else
error( 1, errno, "ошибка вызова recvfrom" );
}
Функция client посылает серверу нулевой байт, читает возвращенную датаграмму, выводит ее в стандартное устройство вывода и завершает программу. Функции recvfrom в коде udphello вполне достаточно одного нулевого байта. После его приема она возвращает управление основной программе, которая и посылает ответную датаграмму.
При одновременном запуске обеих программ выводится обычное приветствий
bsd: $ udphello 9000 &
[1] 448
bsd: $ updhelloc localhost 9000
hello, world
bsd: $
Как всегда, следует вынести стартовый код из main в библиотеку. Обратите внимание, что библиотечной функции, которой дано имя udp_client (листинг 2.11), передается третий аргумент - адрес структуры sockaddr_in; в нее будет помещен адрес и номер порта, переданные в двух первых аргументах.
#include "etcp.h"
SOCKET udp_client( char *host, char *port,
struct sockaddr_in *sap );
Возвращаемое значение: UDP-сокет и заполненная структура sockaddr_in (в случае ошибки завершает программу).
Листинг 2.11. Функция udp_client
1 SOCKET udp_client( char *hname, char *sname,
2 struct sockaddr_in *sap )
3 {
4 SOCKET s;
5 set_address( hname, sname, sap, "udp" );
6 s = socket( AF_INET, SOCK_DGRAM, 0 );
7 if ( !isvalidsockt ( s ) )
8 error( 1, errno, "ошибка вызова socket" );
9 return s;
10 }