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

8.2. Если протокол использует структуры адреса сокета переменной длины,

clilen
может быть слишком длинным. В главе 15 будет показано, что это не вызывает проблем со структурами адреса доменного сокета Unix, но корректным решением будет использовать для функции
sendto
фактическую длину, возвращаемую функцией
recvfrom
.

8.4. Запуск программы

ping
с такими параметрами позволяет просмотреть ICMP-сообщения, получаемые узлом, на котором она запущена. Мы используем уменьшенное количество отправляемых пакетов вместо обычного значения 1 пакет в секунду, только чтобы уменьшить объем выводимой на экран информации. Если запустить наш UDP-клиент на узле
solaris
, указав IP-адрес сервера 192.168.42.1, а затем запустить программу
ping
, получим следующий вывод:

aix % <b>ping -v -I 60 127.0.0.1</b>

PING 127.0.0.1: {127.0.0.1}: 56 data bytes

64 bytes from 127 0.0.1: icmp_seq=0 ttl=255 time=0 ms

36 bytes from 192.168.42.1: Destination Port Unreachable

Vr HL TOS  Len   ID Fig  Off TTL Pro cks  Src Dst Data

4   5  00 0022 0007 0   0000  1e  11 c770 192 168 42.2 192.168.42.1

UDP: from port 40645. to port 9877 (decimal)

ПРИМЕЧАНИЕ

He все версии ping выводят сообщения об ICMP-ошибках, даже если задан параметр -v.

8.5. Прослушиваемый сокет может иметь приемный буфер определенного размера, но прослушиваемым TCP-сокетом данные никогда не принимаются. Большинство реализаций не выделяют заранее память под буферы отправки и приема. Размеры буферов сокета, определяемые параметрами

SO_SNDBUF
и
SO_RCVBUF
, являются предельными значениями для соответствующего сокета.

8.6. Запустим программу

sock
с параметром
-u
(использовать UDP) и параметром
-l
(определяет локальный адрес и порт) на многоинтерфейсном узле
freebsd
.

freebsd % <b>sock -u -l 12.106.32.254.4444 192.168.42.2 8888</b>

<b>hello</b>

Локальный IP-адрес подключен к Интернету (см. рис. 1.7), но чтобы достичь получателя, дейтаграмма должна выйти через другой интерфейс. Наблюдая за сетью с помощью программы

tcpdump
, мы увидим, что IP-адрес отправителя, связанный с клиентом, не является адресом исходящего интерфейса.

14:28:29.614846 12.106.32.254.444 &gt; 192.168.42.2.8888. udp 6

14:28:29.615255 192.168.42.2 &gt; 12 106.32.254: icmp: 192.168 42.2

udp port 8888 unreachable

8.7. Использование функции

printf
на стороне клиента приведет к возникновению задержки между отправками дейтаграмм, что позволит серверу получать большее количество дейтаграмм. Использование функции
printf
на стороне сервера приведет к тому, что сервер будет терять большее количество дейтаграмм.

8.8. Наибольший размер IPv4-дейтаграммы составляет 65 535 байт и ограничивается 16-разрядным полем полной длины, показанным на рис. А.1. IP-заголовок требует 20 байт, UDP-заголовок — 8 байт, и для пользовательских данных остается не более 65 507 байт. В IPv6 (без поддержки джумбограмм) размер IP-заголовка составляет 40 байт, и под пользовательские данные отводится 65 487 байт.

В листинге Д.3 приведена новая версия

dg_cli
. Если забыть установить размер буфера отправки, Беркли-ядра возвратят из функции
sendto
ошибку
EMSGSIZE
, поскольку размер буфера отправки сокета обычно меньше, чем максимально возможный размер UDP-дейтаграммы (чтобы убедиться в этом, выполните упражнение 7.1).

Листинг Д.3. Запись дейтаграммы UDP/IPv4 максимального размера

//udpcliserv/dgclibig.c

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

 2 #undef MAXLINE

 3 #define MAXLINE 65507

 4 void

 5 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

 6 {

 7  int size;

 8  char sendline[MAXLINE], recvline[MAXLINE + 1];

 9  ssize_t n;

10  size = 70000;

11  Setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &amp;size, sizeof(size));

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

13  Sendto(sockfd, sendline, MAXLINE, 0, pservaddr, servlen);

14  n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);

15  printf(&quot;received %d bytes\n&quot;, n);

16 }

Но если установить размеры буферов сокета клиента, как показано в листинге Д.3, и запустить программу, сервер ничего не возвратит. С помощью программы

tcpdump
можно убедиться, что клиентская дейтаграмма отправляется серверу, но если в сервер поместить функцию
printf
, вызов функции
recvfrom
не возвратит дейтаграмму. Проблема заключается в том, что приемный буфер UDP-сокета сервера меньше, чем посланная нами дейтаграмма, поэтому дейтаграмма отбрасывается и не доставляется на сокет. В системах BSD/OS это можно проверить, запустив программу
netstat -s
и проверив счетчик, указывающий количество дейтаграмм, отброшенных из-за переполнения буферов сокета (
dropped due to full socket buffers
), до и после получения нашей длинной дейтаграммы. Решением является модификация сервера путем задания размеров буферов приема и отправки сокета.

В большинстве сетей дейтаграмма длиной 65 535 байт фрагментируется. Как отмечалось в разделе 2.9, IP-уровнем должен поддерживаться размер буфера для сборки фрагментов, равный всего лишь 576 байт. Поэтому некоторые узлы не получат дейтаграмму максимального размера, посылаемую в данном упражнении. Кроме того, во многих Беркли-реализациях, включая 4.4BSD-Lite2, имеется ошибка, связанная со знаковыми типами данных, которая не позволяет UDP принимать дейтаграммы больше, чем 32 767 байт (см. строка 95, с. 770 [128]).

Глава 9

9.1. В некоторых ситуациях функция

sctp_peeloff
может оказаться очень полезной. Примером приложения, которому может понадобиться эта функция, является традиционный сервер дейтаграмм, обрабатывающий небольшие транзакции, которому периодически приходится устанавливать долговременные соединения. Чаще всего сервер передает одно-два коротких сообщения, но время от времени поступает запрос на проверку базы сервера, и тогда ему приходится передавать большие объемы данных. В такой ситуации имеет смысл отделить ассоциацию, по которой передаются проверочные данные, для обработки ее отдельным процессом или потоком.

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