UNIX: разработка сетевых приложений
В листинге 8.8 показан вывод программы
.tcpdumpЛистинг 8.8. Вывод программы tcpdump при запуске функции dg_cli
macosx % <b>tcpdump</b>01 0.0 macosx.51139 > freebsd4 9877:udp 1302 0.006180 ( 0.0062) freebsd4 > macosx: icmp: freebsd4 udp port 9877 unreachableВ табл. A.5 мы также видим, что возникшую ошибку ICMP ядро сопоставляет ошибке
, которая соответствует выводу строки сообщенияECONNREFUSED(В соединении отказано) функциейConnection refused.err_sysПРИМЕЧАНИЕК сожалению, не все ядра возвращают сообщения ICMP присоединенному сокету UDP, как мы показали в этом разделе. Обычно ядра реализаций, происходящих от Беркли, возвращают эту ошибку, а ядра System V — не возвращают. Например, если мы запустим тот же клиент на узле Solaris 2.4 и с помощью функции connect соединимся с узлом, на котором не запущен наш сервер, то с помощью программы tcpdump мы сможем убедиться, что ошибка ICMP о недоступности порта возвращается узлом сервера, но вызванная клиентом функция read никогда не завершается. Эта ситуация была исправлена в Solaris 2.5. UnixWare не возвращает ошибку, в то время как AIX, Digital Unix, HP-UX и Linux возвращают.
8.13. Отсутствие управления потоком в UDP
Теперь мы проверим, как влияет на работу приложения отсутствие какого-либо управления потоком в UDP. Сначала мы изменим нашу функцию
так, чтобы она отправляла фиксированное число дейтаграмм. Она больше не будет читать из стандартного потока ввода. В листинге 8.9 показана новая версия функции. Эта функция отправляет серверу 2000 дейтаграмм UDP по 1400 байт каждая.dg_cliЛистинг 8.9. Функция dg_cli, отсылающая фиксированное число дейтаграмм серверу
//udpcliserv/dgcliloop1.c1 #include "unp.h"2 #define NDG 2000 /* количество дейтаграмм для отправки */3 #define DGLEN 1400 /* длина каждой дейтаграммы */4 void5 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)6 {7 int i;8 char sendline[DGLEN];9 for (i = 0; i < NDG; i++) {10 Sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);11 }12 }Затем мы изменяем сервер так, чтобы он получал дейтаграммы и считал число полученных дейтаграмм. Сервер больше не отражает дейтаграммы обратно клиенту. В листинге 8.10 показана новая функция
. Когда мы завершаем процесс сервера нажатием клавиши прерывания на терминале (что приводит к отправке сигналаdg_echoпроцессу), сервер выводит число полученных дейтаграмм и завершается.SIGINTЛистинг 8.10. Функция dg_echo, считающая полученные дейтаграммы
//udpcliserv/dgecholoop1.c1 #include "unp.h"2 static void recvfrom_int(int);3 static int count;4 void5 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)6 {7 socklen_t len;8 char mesg[MAXLINE];9 Signal (SIGINT, recvfrom_int);10 for (;;) {11 len = clilen;12 Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);13 count++;14 }15 }16 static void17 recvfrom_int(int signo)18 {19 printf("\nreceived %d datagrams\n", count);20 exit(0);21 }Теперь мы запускаем сервер на узле
, который представляет собой медленный компьютер SPARCStation. Клиент мы запускаем в значительно более быстрой системе RS/6000 с операционной системойfreebsd. Они соединены друг с другом напрямую каналом Ethernet на 100 Мбит/с. Кроме того, мы запускаем программуaixна узле сервера и до, и после запуска клиента и сервера, поскольку выводимая статистика покажет, сколько дейтаграмм мы потеряли. В листинге 8.11 показан вывод сервера.netstat -sЛистинг 8.11. Вывод на узле сервера
freebsd % <b>netstat -s -p udp</b>udp:71208 datagrams received0 with incomplete header0 with bad data length field0 with bad checksum0 with no checksum832 dropped due to no socket16 broadcast/multicast datagrams dropped due to no socket1971 dropped due to full socket buffers0 not for hashed pcb68389 delivered137685 datagrams outputfreebsd % <b>udpserv06</b> <i>запускаем наш сервер</i><i> клиент посылает дейтаграммы</i><b>^C </b><i>для окончания работы клиента вводим наш символ прерывания</i>freebsd % <b>netstat -s -р udp</b>udp73208 datagrams received0 with incomplete header0 with bad data length field