22 bzero(∈_zero, sizeof(struct in_addr)); /* IPv4-адрес, состоящий
из одних нулей */
23 for (;;) {
24 len = clilen;
25 flags = 0;
26 n = Recvfrom_flags(sockfd, mesg, MAXLINE, &flags,
27 pcliaddr, &len, &pktinfo);
28 printf("%d-byte datagram from %s", n, Sock_ntop(pcliaddr, len));
29 if (memcmp(&pktinfo.ipi_addr, ∈_zero, sizeof(in_zero)) != 0)
30 printf(", to %s", Inet_ntop(AF_INET, &pktinfo.ipi_addr,
31 str, sizeof(str)));
32 if (pktinfo.ipi_ifindex > 0)
33 printf(", recv i/f = %s",
34 If_indextoname(pktinfо.ipi_ifindex, ifname));
35 #ifdef MSG_TRUNC
36 if (flags & MSG_TRUNC)
37 printf(" (datagram truncated)");
38 #endif
39 #ifdef MSG_CTRUNC
40 if (flags & MSG_CTRUNC)
41 printf(" (control info truncated)");
42 #endif
43 #ifdef MSG_BCAST
44 if (flags & MSG_BCAST)
45 printf(" (broadcast)");
46 #endif
47 #ifdef MSG_MCAST
48 if (flags & MSG_MCAST)
49 printf(" (multicast)");
50 #endif
51 printf("\n");
52 Sendto(sockfd, mesg, n, 0, pcliaddr, len);
53 }
54 }
2-3
Мы удаляем существующее определение MAXLINE
, имеющееся в нашем заголовочном файле unp.h
, и задаем новое значение — 20. Это позволит нам увидеть, что произойдет, когда мы получим дейтаграмму UDP, превосходящую размер буфера, переданного функции (в данном случае функции recvmsg
).
14-21
Если параметр сокета IP_RECVDSTADDR
определен, мы включаем его. Аналогично включается параметр сокета IP_RECVIF
.
24-28
Дейтаграмма читается с помощью вызова функции recvfrom_flags
. IP-адрес отправителя и порт ответа сервера преобразуются в формат представления функцией sock_ntop
.
29-31
Если возвращаемый IP-адрес ненулевой, он преобразуется в формат представления функцией inet_ntop
и выводится.
32-34
Если индекс интерфейса ненулевой, его имя будет возвращено функцией if_indextoname
. Это имя наша функция печатает на экране.
35-51
Мы проверяем четыре дополнительных флага и выводим сообщение, если какие-либо из них установлены.
22.3. Обрезанные дейтаграммы
В системах, происходящих от BSD, при получении UDP-дейтаграммы, размер которой больше буфера приложения, функция recvmsg устанавливает флаг MSG_TRUNC
в элементе msg_flags
структуры msghdr
(см. табл. 14.2). Все Беркли-реализации, поддерживающие структуру msghdr
с элементом msg_flags
, обеспечивают это уведомление.
Это пример флага, который должен быть возвращен процессу ядром. В разделе 14.3 мы упомянули о проблеме разработки функций recv и recvfrom: их аргумент flags является целым числом, что позволяет передавать флаги от процесса к ядру, но не наоборот.
К сожалению, не все реализации подобным образом обрабатывают ситуацию, когда размер дейтаграммы UDP оказывается больше, чем предполагалось. Возможны три сценария:
1. Лишние байты игнорируются, и приложение получает флаг MSG_TRUNC
, что требует вызова функции recvmsg
.
2. Игнорирование лишних байтов без уведомления приложения.
3. Сохранение лишних байтов и возвращение их в последующих операциях чтения на сокете.
POSIX задает первый тип поведения: игнорирование лишних байтов и установку флага MSG_TRUNC. Ранние реализации SVR4 действуют по третьему сценарию.