Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
50 }
51 #endif
52 #ifdef IP_RECVIF
53 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) {
54 struct sockaddr_dl *sdl;
55 sdl = (struct sockaddr_dl*)CMSG_DATA(cmptr);
56 pktp->ipi_ifindex = sdl->sdl_index;
57 continue;
58 }
59 #endif
60 err_quit("unknown ancillary data, len = %d, level = %d, type = %d",
61 cmptr->cmsg_len, cmptr->cmsg_level, cmptr->cmsg_type);
62 }
63 return(n);
64 #endif /* HAVE_MSGHDR_MSG_CONTROL */
65 }
34-37 Если реализация не поддерживает элемента msg_control, мы просто обнуляем возвращаемые флаги и завершаем функцию. Оставшаяся часть функции обрабатывает информацию, содержащуюся в структуре msg_control.
38-41 Мы возвращаем значение msg_flagsи передаем управление вызывающей функции в том случае, если нет никакой управляющей информации, управляющая информация была обрезана или вызывающий процесс не требует возвращения структуры unp_in_pktinfo.
42-43 Мы обрабатываем произвольное количество объектов вспомогательных данных с помощью макросов CMSG_FIRSTHDRи CMSG_NEXTHDR.
47-54 Если в составе управляющей информации был возвращен IP-адрес получателя (см. рис. 14.2), он возвращается вызывающему процессу.
55-63 Если в составе управляющей информации был возвращен индекс интерфейса, он возвращается вызывающему процессу. На рис. 22.1 показано содержимое возвращенного объекта вспомогательных данных.
Рис. 22.1. Объект вспомогательных данных, возвращаемый для параметра IP_RECVIF
Вспомните структуру адреса сокета канального уровня (см. листинг 18.1). Данные, возвращаемые в объекте вспомогательных данных, представлены в одной из этих структур, но длины трех элементов являются нулевыми (длина имени, адреса и селектора). Следовательно, нет никакой необходимости указывать эти значения, и таким образом структура имеет размер 8 байт, а не 20, как было в листинге 18.1. Возвращаемая нами информация — это индекс интерфейса.
Пример: вывод IP-адреса получателя и флага обрезки дейтаграммы
Для проверки нашей функции мы изменим функцию dg_echo(см. листинг 8.2) так, чтобы она вызывала функцию recvfrom_flagsвместо функции recvfrom. Новая версия функции dg_echoпоказана в листинге 22.3.
Листинг 22.3. Функция dg_echo, вызывающая нашу функцию recvfrom_flags
//advio/dgechoaddr.c
1 #include "unpifi.h"
2 #undef MAXLINE
3 #define MAXLINE 20 /* устанавливаем новое значение, чтобы
пронаблюдать обрезку дейтаграмм */
4 void
5 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
6 {
7 int flags;
8 const int on = 1;
9 socklen_t len;
10 ssize_t n;
11 char mesg[MAXLINE], str[INET6_ADDRSTRLEN], ifname[IFNAMSIZ];
12 struct in_addr in_zero;
13 struct in_pktinfo pktinfo;
14 #ifdef IP_RECVDSTADDR
15 if (setsockopt(sockfd, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) < 0)
16 err_ret("setsockopt of IP_RECVDSTADDR");
17 #endif
18 #ifdef IP_RECVIF
19 if (setsockopt(sockfd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
20 err_ret("setsockopt of IP_RECVIF");
21 #endif
22 bzero(&in_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, &in_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 действуют по третьему сценарию.
Читать дальшеИнтервал:
Закладка: