Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
8 }
Функция send_v4
, приведенная в листинге 28.10, строит ICMPv4 сообщение эхо-запроса и записывает его в символьный сокет.
Листинг 28.10. Функция send_v4: построение эхо-запроса ICMPv4 и его отправка
//ping/send_v4.c
1 #include "ping.h"
2 void
3 send_v4(void)
4 {
5 int len;
6 struct icmp *icmp;
7 icmp = (struct icmp*)sendbuf;
8 icmp->icmp_type = ICMP_ECHO;
9 icmp->icmp_code = 0;
10 icmp->icmp_id = pid;
11 icmp->icmp_seq = nsent++;
12 memset(icmp->icmp_data, 0xa5, datalen); /* заполнение по шаблону */
13 Gettimeofday((struct timeval*)icmp->icmp_data, NULL);
14 len = 8 + datalen; /* контрольная сумма по заголовку и данным */
15 icmp->icmp_cksum = 0;
16 icmp->icmp_cksum = in_cksum((u_short*)icmp, len);
17 Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);
18 }
7-13
ICMPv4 сообщение сформировано. В поле идентификатора установлен идентификатор нашего процесса, а порядковый номер установлен как глобальная переменная nset
, которая затем увеличивается на 1 для следующего пакета. Текущее время сохраняется в части данных ICMP-сообщения.
14-16
Для вычисления контрольной суммы ICMP значение поля контрольной суммы устанавливается равным 0, затем вызывается функция in_cksum
, а результат сохраняется в поле контрольной суммы. Контрольная сумма ICMPv4 вычисляется по ICMPv4-заголовку и всем следующим за ним данным.
17
ICMP-сообщение отправлено на символьный сокет. Поскольку параметр сокета IP_HDRINCL
не установлен, ядро составляет заголовок IPv4 и добавляет его в начало нашего буфера.
Контрольная сумма Интернета является суммой обратных кодов 16-разрядных значений. Если длина данных является нечетным числом, то для вычисления контрольной суммы к данным дописывается один нулевой байт. Перед вычислением контрольной суммы поле контрольной суммы должно быть установлено в 0. Такой алгоритм применяется для вычисления контрольных сумм IPv4, ICMPv4, IGMPv4, ICMPv6, UDP и TCP. В RFC 1071 [12] содержится дополнительная информация и несколько числовых примеров. В разделе 8.7 книги [128] более подробно рассказывается об этом алгоритме, а также приводится более эффективная его реализация. В нашем случае контрольную сумму вычисляет функция in_cksum
, приведенная в листинге 28.11.
Листинг 28.11. Функция in_cksum: вычисление контрольной суммы Интернета
//libfree/in_cksum.c
1 uint16_t
2 in_cksum(uint16_t *addr, int len)
3 {
4 int nleft = len;
5 uint32_t sum = 0;
6 uint16_t *w = addr;
7 uint16_t answer = 0;
8 /*
9 * Наш алгоритм прост: к 32-разрядному аккумулятору sum мы добавляем
10 * 16-разрядные слова, а затем записываем все биты переноса из старших
11 * 16 разрядов в младшие 16 разрядов.
12 */
13 while (nleft > 1) {
14 sum += *w++;
15 nleft -= 2;
16 }
17 /* при необходимости добавляем четный байт */
18 if (nleft == 1) {
19 *(unsigned char*)(&answer) = *(unsigned char*)w;
20 sum += answer;
21 }
22 /* перемещение битов переноса из старших 16 разрядов в младшие */
23 sum = (sum >> 16) + (sum & 0xffff); /* добавление старших 16 к младшим */
24 sum += (sum >> 16); /* добавление переноса */
25 answer = ~sum; /* обрезаем по 16 разрядам */
26 return(answer);
27 }
1-27
Первый цикл while
вычисляет сумму всех 16-битовых значений. Если длина нечетная, то к сумме добавляется конечный байт. Алгоритм, приведенный в листинге 28.11, является простым алгоритмом, подходящим для программы ping
, но неудовлетворительным для больших объемов вычислений контрольных сумм, производимых ядром.
Эта функция взята из общедоступной версии программы ping, написанной Майком Мюссом (Mike Muuss).
Последней функцией нашей программы ping
является функция send_v6
, приведенная в листинге 28.12, которая формирует и посылает эхо-запросы ICMPv6.
Функция send_v6
аналогична функции send_v4
, но обратите внимание, что она не вычисляет контрольную сумму. Как отмечалось ранее, поскольку для вычисления контрольной суммы ICMPv6 используется адрес отправителя из IPv6-заголовка, данная контрольная сумма вычисляется для нас ядром, после того как ядро выяснит адрес отправителя.
Листинг 28.12. Функция send_v6: построение и отправка ICMPv6-сообщения эхо-запроса
//ping/send_v6.c
1 #include "ping.h"
2 void
3 send_v6()
4 {
5 #ifdef IPV6
6 int len;
7 struct icmp6_hdr *icmp6;
8 icmp6 = (struct icmp6_hdr*)sendbuf,
9 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
10 icmp6->icmp6_code = 0;
11 icmp6->icmp6_id = pid;
12 icmp6->icmp6_seq = nsent++;
13 memset((icmp6 + 1), 0xa5, datalen); /* заполнение по шаблону */
14 Gettimeofday((struct timeval*)(icmp6 + 1), NULL);
15 len = 8 + datalen; /* 8-байтовый заголовок ICMPv6 */
16 Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);
17 /* ядро вычисляет и сохраняет контрольную сумму само */
18 #endif /* IPV6 */
19 }
28.6. Программа traceroute
В этом разделе мы приведем собственную версию программы traceroute
. Как и в случае с программой ping
, приведенной в предыдущем разделе, мы представляем нашу собственную, а не общедоступную версию. Это делается для того, чтобы во-первых, получить версию, поддерживающую как IPv4, так и IPv6, а во-вторых, не отвлекаться на множество параметров, не относящихся к обсуждению сетевого программирования.
Программа traceroute
позволяет нам проследить путь IP-дейтаграмм от нашего узла до получателя. Ее действие довольно просто, а в главе 8 книги [111] оно детально описано со множеством примеров.
В версии IPv6 программа traceroute
использует поле TTL (в версии IPv4) или поле предельного количества транзитных узлов (называемое также полем ограничения пересылок), а также два типа ICMP-сообщений. Эта программа начинает свою работу с отправки UDP-дейтаграммы получателю, причем полю TTL (ограничения пересылок) присваивается значение 1. Такая дейтаграмма вынуждает первый маршрутизатор отправить ICMP-сообщение об ошибке «Time exceeded in transit» (Превышено время передачи). Затем значение TTL увеличивается на 1 и посылается следующая UDP-дейтаграмма, которая достигает следующего маршрутизатора. Когда UDP-дейтаграмма достигает конечного получателя, необходимо заставить узел вернуть ICMP-ошибку Port unreachable
(Порт недоступен). Для этого UDP-дейтаграмма посылается на случайный порт, который (как можно надеяться) не используется на данном узле.
Ранние версии программы traceroute
могли устанавливать поле TTL в заголовке IPv4 только с помощью параметра сокета IP_HDRINCL
путем построения своего собственного заголовка. Однако современные системы поддерживают параметр сокета IP_TTL
, позволяющий определить значение TTL для исходящих дейтаграмм. (Данный параметр сокета впервые был представлен в выпуске 4.3BSD Reno.) Проще установить данный параметр сокета, чем полностью формировать IPv4-заголовок (хотя в разделе 29.7 показано, как строить собственные заголовки IPv4 и UDP). Параметр сокета IPv6 IPV6_UNICAST_HOPS
позволяет контролировать поле предельного количества транзитных узлов (ограничения пересылок) в дейтаграммах IPv6.
Интервал:
Закладка: