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




Совет 30. Разберитесь, что такое подсоединенный UDP-сокет - часть 4


Иногда нужно получать датаграммы только от одного приложения. Получающее приложение добивается этого, соединившись со своим партнером. Чтобы увидеть, как это работает, напишем UDP-сервер эхо-контроля, который соединяется с первым клиентом, отправившим датаграмму (листинг 3.35).

Листинг 3.35. UDP-сервер эхо-контроля, выполняющий соединение

1    #include   "etcp.h"     :

2    int main( int argc, char **argv )

3    {

4    struct sockaddr_in peer;

5    SOCKET s;

6    int rс;

7    int len;

8    char buf[ 120 ];

9    INIT();

10   s = udp_server( NULL, argv[ 1 ] ) ;

11   len = sizeof( peer );

12   rс = recvfrom( s, buf, sizeoff buf ),

13   0, ( struct sockaddr * )&peer, &len );

14   if ( rс < 0 )

15     error( 1, errno, "ошибка вызова recvfrom" );

16   if ( connect( s, ( struct sockaddr * )&peer, len ) )

17     error( 1, errno, "ошибка вызова connect" );

18   while ( strncmp( buf, "done", 4 ) != 0 )

19   {

20     if ( send( s, buf, rс, 0 ) < 0 )

21      error( 1, errno, "ошибка вызова send" );

22     rc = recv( s, buf, sizeof( buf ), 0 );

23     if ( rс < 0 )

24      error( 1, errno, "ошибка вызова recv" );

25   }

26   EXIT( 0 );

27   }

9-15 Выполняем стандартную инициализацию UDP и получаем первую датаграмму, сохраняя при этом адрес и порт отправителя в переменной peer.

16-17 Соединяемся с отправителем.

18-25 В цикле отсылаем копии полученных датаграмм, пока не придет датаграмма, содержащая единственное слово «done».

Для экспериментов с сервером udpconnserv можно воспользоваться клиентом udpconn2. Сначала запускается сервер для прослушивания порта 9000 в ожи­дании датаграмм:

udpconnserv  9000

а затем запускаются две копии udpconn2, каждая в своем окне.

bsd: $  udpconn2 bsd 9000

one

one

three

three

done

^C

bsd:  $

bsd: $  udpconn2 bsd 9000

two

udpconn2: ошибка вызова  recvfroin:

   Connection refused   (61)

bsd:  $

Когда в первом окне вы набираете one, сервер udpconnserv возвращает копию датаграммы. Затем во втором окне вводите two, но recvf rom возвращает код ошибки ECONNREFUSED. Это происходит потому, что UDP вернул ICMP-сообщение о недоступности порта, так как ваш сервер уже соединился с первым экземпляром udpconn2 и не принимает датаграммы с других адресов.

Примечание: Адреса отправителя у обоих экземпляров udpconn2, конечно, одинаковы, но эфемерные порты, выбранные стеком TCP/IP, различны. В первом окне вы набираете three, дабы убедиться, что udpconnserv все еще функционирует, а затем — done, чтобы остановить сервер. В конце прерываем вручную первый экземпляр udpconn2.

Как видите, udpconnserv не только отказывается принимать датаграммы от другого отправителя, но также информирует приложение об этом факте, посылая ICMP-сообщение. Разумеется, чтобы получить это сообщение, клиент также должен подсоединиться к серверу. Если бы вы прогнали этот тест с помощью первоначальной версии клиента udpclient вместо udpconn2, то второй экземпляр клента просто «завис» после ввода слова «done».




Содержание  Назад  Вперед