Литмир - Электронная Библиотека
Содержание  
A
A

 0 with bad checksum

 0 with no checksum

 832 dropped due to no socket

 16 broadcast/multicast datagrams dropped due to no socket

 3941 dropped due to full socket buffers

 0 not for hashed pcb

 68419 delivered

 137685 datagrams output

Клиент отправил 2000 дейтаграмм, но приложение-сервер получило только 30 из них, что означает уровень потерь 98%. Ни сервер, ни клиент не получают сообщения о том, что эти дейтаграммы потеряны. Как мы и говорили, UDP не имеет возможности управления потоком — он ненадежен. Как мы показали, для отправителя UDP не составляет труда переполнить буфер получателя.

Если мы посмотрим на вывод программы

netstat
, то увидим, что общее число дейтаграмм, полученных узлом сервера (не приложением-сервером) равно 2000 (73 208 – 71 208). Счетчик
dropped due to full socket buffers
(отброшено из-за переполнения буферов сокета) показывает, сколько дейтаграмм было получено UDP и проигнорировано из-за того, что приемный буфер принимающего сокета был полон [128, с. 775]. Это значение равно 1970 (3941 – 1971), что при добавлении к выводу счетчика дейтаграмм, полученных приложением (30), дает 2000 дейтаграмм, полученных узлом. К сожалению, счетчик дейтаграмм, отброшенных из-за заполненного буфера, в программе
netstat
распространяется на всю систему. Не существует способа определить, на какие приложения (например, какие порты UDP) это влияет.

Число дейтаграмм, полученных сервером в этом примере, недетерминировано. Оно зависит от многих факторов, таких как нагрузка сети, загруженность узла клиента и узла сервера.

Если мы запустим тот же клиент и тот же сервер, но на этот раз клиент на медленной системе Sun, а сервер на быстрой системе RS/6000, никакие дейтаграммы не теряются.

aix % <b>udpserv06</b>

<b>^?</b> <i>после окончания работы клиента вводим наш символ прерывания</i>

received 2000 datagrams

Приемный буфер сокета UDP

Число дейтаграмм UDP, установленных в очередь UDP, для данного сокета ограничено размером его приемного буфера. Мы можем изменить его с помощью параметра сокета

SO_RCVBUF
, как мы показали в разделе 7.5. В FreeBSD по умолчанию размер приемного буфера сокета UDP равен 42 080 байт, что допускает возможность хранения только 30 из наших 1400-байтовых дейтаграмм. Если мы увеличим размер приемного буфера сокета, то можем рассчитывать, что сервер получит дополнительные дейтаграммы. В листинге 8.12 представлена измененная функция
dg_echo
из листинга 8.10, которая увеличивает размер приемного буфера сокета до 240 Кбайт. Если мы запустим этот сервер в системе Sun, а клиент — в системе RS/6000, то счетчик полученных дейтаграмм будет иметь значение 103. Поскольку это лишь немногим лучше, чем в предыдущем примере с размером буфера, заданным по умолчанию, ясно, что мы пока не получили решения проблемы.

Листинг 8.12. Функция dg_echo, увеличивающая размер приемного буфера сокета

//udpcliserv/dgecholоор2.c

 1 #include &quot;unp.h&quot;

 2 static void recvfrom_int(int);

 3 static int count;

 4 void

 5 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)

 6 {

 7  int n;

 8  socklen_t len;

 9  char mesg[MAXLINE];

10  Signal(SIGINT, recvfrom_int);

11  n = 240 * 1024;

12  Setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &amp;n, sizeof(n));

13  for (;;) {

14   len = clilen;

15   Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &amp;len);

16   count++;

17  }

18 }

19 static void

20 recvfrom_int(int signo)

21 {

22  printf(&quot;\nreceived %d datagrams\n&quot;, count);

23  exit(0);

24 }

ПРИМЕЧАНИЕ

Почему мы устанавливаем размер буфера приема сокета равным 240×1024 байт в листинге 8.12? Максимальный размер приемного буфера сокета в BSD/OS 2.1 по умолчанию равен 262 144 байта (256×1024), но из-за способа размещения буфера в памяти (описанного в главе 2 [128]) он в действительности ограничен до 246 723 байт. Многие более ранние системы, основанные на 4.3BSD, ограничивали размер буфера приема сокета примерно до 52 000 байт.

8.14. Определение исходящего интерфейса для UDP

С помощью присоединенного сокета UDP можно также задавать исходящий интерфейс, который будет использован для отправки дейтаграмм к определенному получателю. Это объясняется побочным эффектом функции

connect
, примененной к сокету UDP: ядро выбирает локальный IP-адрес (предполагается, что процесс еще не вызвал функцию
bind
для явного его задания). Локальный адрес выбирается в процессе поиска адреса получателя в таблице маршрутизации, причем берется основной IP-адрес интерфейса, с которого, согласно таблице, будут отправляться дейтаграммы.

В листинге 8.13 показана простая программа UDP, которая с помощью функции connect соединяется с заданным IP-адресом и затем вызывает функцию

getsockname
, выводя локальный IP-адрес и порт.

Листинг 8.13. Программа UDP, использующая функцию connect для определения исходящего интерфейса

//udpcliserv/udpcli09.c

 1 #include &quot;unp.h&quot;

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int sockfd;

 6  socklen_t len;

 7  struct sockaddr_in cliaddr, servaddr;

 8  if (argc != 2)

104
{"b":"225366","o":1}