Главная страница

Программирование в сетях Windows. Э. Джонс, Д. Оланд


Скачать 2.88 Mb.
НазваниеЭ. Джонс, Д. Оланд
АнкорПрограммирование в сетях Windows.pdf
Дата12.10.2017
Размер2.88 Mb.
Формат файлаpdf
Имя файлаПрограммирование в сетях Windows.pdf
ТипКнига
#9346
страница34 из 50
1   ...   30   31   32   33   34   35   36   37   ...   50

[data size]\n");
printf(" -r record route\n");
printf(" host remote machine to printfC" datasize can be up to 1 KB\n");
ExitProcess(-i); tttxo *
// Функция: FilllCMPData
(Г < asie) ellrtw
{
(evre) т!
}
»+
0)
. cwzp.

4 0 4 ЧАСТЬ II Интерфейс прикладного программирования Winsock .
Листинг 13-1. (продолжение) экИ,
/ / Описание:
т
\
II Вспомогательная функция для заполнения полей нашего запроса void FillICMPData(char *icmp_data, mt datasize) ;|.
IcmpHeader *icmp_hdr = NULL;
char «datapart = NULL; Outr icmp_hdr = (IcmpHeader*)icmp_data; *I \
icmp_hdr->i_type = ICMP_ECHO; // Эхо-запрос ICHP
icmp_hdr->i_code = 0 ; \
icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); о V
icmp_hdr->i_cksum = 0; ; V
icmp_hdr->i_seq = 0; \
%
v
TO. wflY
datapart = icmp_data + sizeof(IcmpHeader); >
// Поместите какие-нибудь данные в буфер memset(datapart,'Е', datasize - sizeof(IcmpHeader));
// Функция: checksum *etv
// "eb,
// Описание:
// Вычисляет 16-битную комплементарную сумму оо»Яа J0 "
// для указанного буфера с заголовком .eeteb i'u
USHORT checksum(USHORT «buffer, i n t size)
unsigned long cksum=0; ajteu :u k
. <
ЧЧ
while (size > 1) , :SN- ' i'
cksum += «buffer++; \
4
size -= sizeof (USHORT); -лц
i f (size) i q
{ i •
cksum += *(UCHAR*)buffer;
cksum = (cksum » 16) + (cksum & Oxffff);
cksum += (cksum »16);
return (USHORT)Ccksum);
// Функция: DecodelPOptions

н»л|"ЛАВА 13 Просты* «Ф^ИЫ 405
Листинг 13-1. (продолжение) Л С г
// Описание: .'о1ТЗл; ••
// При наличии расширенного заголовка находит параметры IP
// в нем и выводит значения параметра записи маршрута ткм ,„Л
void DecodeIPOptions(char *buf, int bytes)
IpOptionHeader «ipopt = NULL;
IN_ADDR maddr; , • «. ttfc-q int i; ,Jt«< r
HOSTENT «host = NULL;
ipopt = (IpOptionHeader *)(buf + 20);
ЭЗ_<Ш] t-itrtqi'..,)
printf("RR: " ) ;
f o r ( i = 0; i < (ipopt->ptr / 4) - 1; i++) ei is* & г ,.^ц
inaddr.S_un.S_addr = i p o p t - > a d d r [ i ] ; {
i f ( i != 0)
p r i n t f ( " " ) ; «s»f >эдкаП \\
host = gethostbyaddr((char *)&inaddr.S_un.S_addr, X
1
»
sizeof(inaddr.S_un.S_addr), AF_INET); Jicwwi)
if (host) }
printf("(X-15s) Xs\n", inet_ntoa(inaddr), host->h_nane); jrnitr e t u r n ; ; ( р з з , jt< J.SOJ: ," ,bt »
// Функция: DecodelCMPHeader
// ;nitJei
// Описание: {
II Ответом является пакет IP. Следует декодировать заголовок IP
// для нахождения данных ICMP ч^ ^XeV Ътч
II >
void DecodeICMPHeader(char «buf, int bytes, tni
struct sockaddr_in *from)
{ • ! m
IpHeader .iphdr = NULL;
IcmpHeader «icmphdr = NULL; ,3Zi? s
unsigned short iphdrlen;
DWORD tick;
static int lcmpcount = 0; «
iphdr = (IpHeader *)buf;
// Количество 32-х битных слов помноженное на 4 равно числу байт
см. след. стр.

4 0 6 ЧАСТЬ II Интерфейс прикладного программирования Wfcwock
Л и с т и н г 1 3 - 1 . (продолжение) (wsmxX4ib®Qf\) . f - £ f ч«»Тй*»И
iphdrlen = iphdr->h_len * 4; \\
t i c k = GetTickCount(); » :вмнв&кг>0 \\
Ю¥ ац птнлбн щР \\
if ( ( i p h d r l e n == MAX_IP_HDR_SIZE) && (licmpcount)X «н« *щовив
и чеч в \\
DecodeIPOptions(buf, bytes); \\
•> tnt Л«><1« -поЛЩОЧ 90 tolov
if (bytes < iphdrlen + ICMP_MIN) }
{
printf("Too few bytes from Xs\n",
inet_ntoa(f rom->sin_addr)); '' *»
}
icmphdr = (IcmpHeader«)(buf + iphdrlen);
if (icmphdr->i_type != ICMP.ECHOREPLY)
{
printf("nonecho type %d recvd\n", icmphdr->i_type)noqf) > x ,0 » xjnoi return; }
// Проверка, что это ICMP-отклик на отправленное нами сообщение!
//
if (icmphdr->i_id != (USHORT)GetCurrentProcessIdO)
{ П
printf("someone else's packet!\n"); n/t-
l
>'-t,
return ; e l *
} '-*
printf("Xd bytes from Xs:", bytes, inet_ntoa(from->sin_addr)); {
p r i n t f ( " icmp_seq = %d. ", icmphdr->i_seq); ;mn?ei p r i n t f ( " time: %d ms", t i c k - icmphdr->tiinestamp);
p r i n t f ( " \ n " ) ;
V.
icmpcount++; t ' Ь
return;
t: .•
щ 41
void ValidateArgs(int argc, ohir **argv)
int 1;
bRecordRoute = FALSE;
lpdest = NULL;
datasize = DEF_PACKET_SIZE;
for(i = 1; i < argc; i++)
{
if ((argv[i][0] == •-') |
wjytf tat
J
J
I (argv[i][0] ==
Лив* п«(1э)
(iSCit» 4J
0 .
= V))
switch (tolower(argv[i][1]))

ГЛАВА 13 Простые сокеты
407
Листинг 13-1. {продолжение)
case ' r
-
: // Параметр записи маршрута
bRecordRoute = TRUE;
i break;
\ default:
usage(argv[O]);
break;
{
eV
else if (isdigit(argv[i][O]))
datasize = atoi(argv[i]);
else «x lpdest = argv[i]; woeu
s s
1С ft
ITO
I I
II Функция: main
•c \\
-э \\
v
•3 \\
-a \\
•>, \\
• *
, \
' • » \ \
V
1
.
// Описание:
// Настраивает простой сокет ICMP и создает заголовок ICMP. Добавляет Ы э т
II соответствующий расширенный заголовок IP и начинает рассылку и_А8Ч
// эхо-запросов ICMP по конечным точкам. Для каждой отправки и в) •*
// приема мы задаем таймаут во избежание простоя, когда конечная }
// точка не отвечает. Принятый пакет декодируется. tnn<3
i n t m a i n ( i n t a r g c , c h a r * * a r g v )
WSADATA wsaData; >тв* ои .що/
SOCKET sockRaw = INVALID_S0CKETfOTt struct soGJttddr.in dest,
from;
i n t *« **
f bread,
*• fromlen = sizeof(from),
timeout = 1000, >J- ret; ,,
char *icmp_data = NULL^.O
T
•recvbuf = NULL; (('
unsigned int addr = 0; ">
USHORT seq_no = 0;
struct hostent *hp = NULL; (8
IpOptionHeader ipopt;

«S»
ем
V\
t
-d
•n)
if (WSAStartup(HAKEW0RD(2, 2), &wsaData) != 0)
{
printf("WSAStartup() failed: Xd\n", GetLastErrorO);
return - 1 ;
см. след. стр.

4 0 8 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 13-1. {продолжение) г-£МнмтсшТ1
} в q М \\ .
J
V a l i d a t e A r g s ( a r g c , a r g v ) ; \\ffl * е
1
DO«-S
// Я о
// Параметрам SO_RCVTIMEO и SO_SNDTIMEO требуется флаг
// WSA_FLAG_OVERLAPPED. Если последний параметр WSASocket - NULL,
// весь ввод-вывод на сокете синхронный, внутренний код ожидания
// пользовательского режима никогда не будет выполнен, а потому {
// окончательно блокируется ввод-вывод в режиме ядра.
// Для сокета, созданного функцией socket, атрибут перекрытого
// ввода-вывода задается автоматически. Однако в данном случае
// создания простого сокета нужно использовать WSASocket.
// . i
// Если вы хотите использовать таймаут с синхронным неперекрытым {
// сокетом, созданным WSASocket с последним параметром
// равным NULL, задайте таймаут функцией select либо задействуйте \\
// WSAEventSelect и укажите таймаут в функции ^чдкн^Ф \\
// WSAWaitForMultipleEvents. \\
// аэмпО \\
sockRaw = WSASocket (AF_INET, SOCK.RAW, IPPROTO_ICMP, NULL, 0,
г
Н \\
WSA_FLAG_OVERLAPPED);
)0
\\
if (sockRaw == INVALID_SOCKET) <
B
\\
{ »qr. \\
printf("WSASocket() failed: Xd\n", WSAGetLaetErrorO); ,',
т у
return -1; \\
if (bRecordRoute) *
II Настройка отправки расширенного заголовка
// IP с каждым ICMP-пакетом fMooe 1-
ZeroMemory(&ipopt, s i z e o f ( i p o p t ) ) ;
ipopt.code = IP_RECORD_ROUTE; // Параметр записи маршрута i p o p t . p t r = 4; // Укажите смещение для первого адреса i p o p t . l e n = 39; // Длина расширенного заголовка ret = setsockopt(sockRaw, IPPROTO_IP, IP_OPTIONS,
t
(char *)&ipopt, s i z e o f ( i p o p t ) ) ; i»
if ( r e t == SOCKET.ERROR) - s
?ol ben.
< , l "
printf("setsockopt(IP_OPTIONS) f a i l e d : X// Настройка таймаутов отправки и приема
// ,t / ' , > - . - bread = setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIHE0, (charOWimeout, sizeof(tinieout));
if(bread == SOCKET.ERROR)
{
printf("setsockopt(SO_RCVTIHEO) f a i l e d : Xd\n". WSAGetLastErrorO);

13 Простые сокеты
4 0 9
Листинг 13-1. (продолжение) т«.
return - 1 ; ->
> .1
timeout = 1000;
bread = setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, slzeof(timeout));
if (bread == SOCKET_ERROR)
{
pnntf("setsockopt(SO_SNDTIMEO) failed: Xd\n", WSAGetLastErrorQ); ,,.-,,,_
return - 1 ;
}
memset(&dest, 0, sizeof(dest)); '"
// ,"'//
// При необходимости разрешается имя конечной точки "

*
II '"
dest.sin_family = AF_INET; •' "
if ((dest.sin_addr.s_addr = inet_addr(lpdest)) == INADDR.NONE) f >i-
{ ij
if ((hp = gethostbyname(lpdest)) != NULL) ;
memcpy(&(dest.sin_addr), hp->h_addr, hp->h_length);
dest.sin_family = hp->h_addrtype;
printf("dest.sin_addr = Xs\n", inet_ntoa(dest.sin_addr));
else
i-
ru-
printf("gethostbyname() failed: Xd\n", WSAGetLastErrorO); }ii . >t.> п return - 1 ; , <, >
! я
// Создание ICMP-пакета
datasize += sizeof(IcmpHeader);
icmp.data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PACKET);
recvbuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PACKET);
if (!icmp_data)
<
printf("HeapAlloc() failed: Xd\n", GetLastErrorO);
return -1;
memset(icmp_data,0,MAX_PACKET);
FillICMPData(icmp_data,datasize);
// Начало отправки/приема ICMP-пакетов
whiled)
i
см. след. стр.

410 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 13-1. {продолжение) it ч

- static int nCount = 0; ,f muJei int bwrote, {
if (nCount++ == 4) ei»Te* • bend break, .» beei4) M.
}
((IcmpHeader»)icmp_data)->i_cksum = 0;
((IcmpHeader*)icmp_data)->timestamp = 6etTickCount();
((IcmpHeader*)icmp_data)->i_seq = seq_no++; {
((IcmpHeader*)icmp_data)->i_cksum = lid *)r»3*ea checksum((USHORT*)icmp_data, datasize); » < \\
bwrote = sendto(sockRaw, icmp_data, datasize, 0, (struct sockaddr*)&dest, sizeof(dest));
if (bwrote == SOCKET_ERROR)
{
if (WSAGetLastErrorO == WSAETIMEDOUT) • >
{ *e ) i i printf('timed out\n"); }
continue;
} ма
pnntf('sendtoO failed- Xd\n", WSAGetLastErrorO); )
return -1, <
> M l *
if (bwrote < datasize) }
{ iin
printf("Wrote %d bytes\n", bwrote);
}
bread = recvfrom(sockRaw, recvbuf, MAX_PACKET, 0, (struct sockaddr*)&from,
&fromlen);
if (bread == SOCKET_ERROR) \
{ e m ^ s " W 0 I e»H«fteo0 \\
if (WSAGetLastErrorO == WSAETIMEDOUT) \\
{
r
'
printf("timed out\n");
continue;
}
printf("recvfrom() failed' Xd\n", WSAGetLastErrorO); b.qets-.') >i return -1; )
} I {,). )-.
DecodeICMPHeader(recvbuf, bread, &from);
о ,{
Sleep(IOOO), »m
} ЧР
II Очистка 'i
//
if (sockRaw "= INVALID_SOCKET)
closesocket(sockRaw),
HeapFree(GetProcessHeap(), 0, recvbuf);
HeapFree(GetProcessHeap(), 0, icmp_data),

ГЛАВА 13 Простые сокеты
411
Листинг 13-1. {продолжение)
WSACleanupO;
return 0;
Одна из значимых особенностей этого примера Ping — использование параметра сокета IP_OPTIONS Мы применяем параметр записи маршрута IP,
чтобы когда ICMP-пакет достигнет маршрутизатора, его IP-адрес был добав- лен в расширенный заголовок IP в месте, обозначенном полем смещения
Это смещение увеличивается на 4 каждый раз, когда маршрутизатор добав- ляет адрес, поскольку для IP версии 4 длина IP-адреса равна 4 байтам В этой книге мы не касаемся IP версии 6, поскольку имеющиеся платформы Win- dows пока не поддерживают ее После приема эхо-ответа расширенный за-
головок (option header) декодируется и на экран выводятся IP-адреса и име- на узлов пройденных маршрутизаторов. (Подробнее о других типах доступ- ных параметров IP — в главе 9)
Программа Traceroute
Это еще один ценный сетевой инструмент, позволяющий определять IP-ад- реса маршрутизаторов, проходимых запросом на пути к определенному узлу
Ping также позволяет определить IP-адреса маршрутизаторов, используя па- раметр записи маршрута в расширенном заголовке IP, однако его возмож- ности ограничены всего девятью транзитами — максимальным простран- ством, предназначенным для адресов в расширенном заголовке Транзит происходит всякий раз, когда IP-дейтаграмма проходит маршрутизатор для перехода в другую физическую сеть Для маршрутов с более чем девятью та- кими переходами используйте Traceroute
В основе Traceroute лежит идея отправки UDP-пакета адресату и посте- пенного изменения времени жизни (time-to-live, TTL) Первоначально TTL
пакета равен 1, и когда пакет достигает первого маршрутизатора, его TTL
сбрасывае гея, и маршрутизатор генерирует ICMP-пакет со сведениями о пре- вышении лимита времени Тогда начальное значение TTL увеличивается на
1, так что на сей раз UDP-пакет достигает следующего маршрутизатора, а тот тоже отсылает ICMP-пакет по превышению лимита времени Совокупность этих ICMP-сообщений дает список IP-адресов, пройденных на пути к конеч- ной точке Когда TTL увеличится настолько, что UDP-пакет достигнет иско- мой конечной точки, возвращается ICMP-сообщение о недостижимости пор- та, поскольку на получателе ни один процесс не ждет вашего сообщения
Traceroute полезна тем, что дает подробнейшую информацию о маршруте до конкретного узла — это часто необходимо при многоадресной передаче или проблемах с маршрутизацией Впрочем, программная реализация функ- циональности Traceroute необходима реже, чем Ping
Существует два способа выполнить программу Traceroute Во-первых, вы можете использовать UDP-пакеты и отправлять дейтаграммы, постепенно изменяя TTL Каждый раз по истечении TTL будет возвращаться ICMP-сообще-

4 1 2 ЧАСТЬ II Интерфейс прикладного программирования Wmsock ние. Этот метод требует наличия обычного сокета протокола UDP (см. главу
7) для отправки сообщений, а также сокета типа SOCK_RAW под протокол
IPPROTOJCMP для чтения возвращенных сообщений. TTL для UDP-сокета можно контролировать через параметр сокета IPJTTL, либо создать UDP-co- кет и использовать параметр IP_HDRINCL (см. далее в этой главе), чтобы вруч- ную задать TTL в заголовке IP. Но это чересчур трудоемкая задача.
Другой метод — просто отправлять ICMP-пакеты адресату с постепенным изменением TTL В результате также возвращаются ICMP-сообщения об ошиб- ке по истечении TTL. Это похоже на пример Ping, в том смысле, что требу- ется только один сокет (для протокола ICMP). В папке с примерами на при- лагаемом компакт-диске есть пример реализации Traceroute с использова- нием ICMP-пакетов (Traceroute.c).
Протокол IGMP
Протокол IGMP используется многоадресным вещанием IP для управления членством в многоадресных группах. (Об использовании Winsock для вступ- ления в такую группу и выхода из нее — в главе 11.) Когда программа соеди- няется с многоадресной группой, она отправляет ЮМР-сообщение каждому маршрутизатору локальной сети, используя специальный адрес группы всех маршрутизаторов — 224-0.0.2. Сообщение информирует маршрутизаторы о наличии получателя для любых данных, предназначенных для многоадресной группы. Только после этого маршрутизаторы начинают перенаправлять дан- ные группы зарегистрированному получателю. Без этой возможности много- адресная передача данных ничем не отличалась бы от широковещания.
Некоторую путаницу создают две версии протокола IGMP: версии 1 и 2,
которые описаны в RFC 1112 и RFC 2236 соответственно. Главное различие между ними — версия 1 не позволяет узлу дать маршрутизатору указание о прекращении отправления данных, предназначенных для многоадресной группы. Другими словами, когда узел решает выйти из группы, он не уведом- ляет об этом маршрутизатор, который продолжает распространять данные для этой группы, пока не убеждается в отсутствии отклика. Версия 2 предус- мотривает четкое и немедленное уведомление узлами маршрутизаторов о выходе из группы. Кроме того, немного различаются форматы заголовка двух версий (рис. 13-2 и 13-3)- Оба заголовка просты, поскольку имеют раз- мер всего 8 байт. ' ч i <
ton йерсия \ШР
, 8-бишзб яеяегюльзуеше толе
16-йшая контрольная сумма НЗМР
зг-i

Рис. 13-2. Формат заголовка IGMPvi

Г Л А В А 13 Простые сокеты
413 8-битный тип IGMP
8-битное поле максимального времени ожидания
16-битная контрольная сумма 1GMP
32-битный адрес многоадресной рассылки (fP-адрес класса D)
Рис. 13-3. Формат заголовка IGMPv2
В версии 1 два четырехбитных поля: первое — версия IGMP, второе — тип сообщения. В версии 2 эти два поля заменяет одно восьмибитное Неисполь- зуемое в версии 1 поле становится полем максимального времени ожидания
(Max Response Time). Оно используется только при передаче запроса о член- стве: определяет максимальное время ожидания ответа в десятых долях се- кунды. Во всех других случаях отправитель задает в этом поле 0, и получа- тели игнорируют его.
Для IGMPvl полем версии всегда является первое, а в поле типа задается одно из двух возможных значений- 0x1 — запрос о членстве в группе, 0x2 —
отчет о членстве. Маршрутизаторы используют запрос о членстве узла (0x1),
чтобы определить, к какой многоадресной группе причислен узел В этом случае полю адреса группы присваивается 0. Маршрутизатор отправляет пакет по адресу всех узлов (224.0 0 1)
Если узлы по-прежнему являются членами какой-либо группы, каждый из них возвращает отчет о членстве (тип ЮМР-сообщения 0x2) вместе с адре- сом группы, в которой зарегистрирован. При первичной регистрации узла в группе сообщение с отчетом о членстве также отправляется на групповой адрес маршрутизаторов.
В версии 2 протокола IGMP предусмотрены следующие типы сообщений.
Ш 0x11 — запрос о членстве;
0x12 — отчет о членстве версии 1;
В 0x16 — отчет о членстве версии 2; ; j ^
Ш 0x17 — выход из группы. ^„
t
.
Как видите, добавлены два новых типа сообщения: отчет версии 2 (0x16)
и выход из группы (0x17). Два других сообщения аналогичны сообщениям версии 1 (запрос и отчет по членству), хотя их значения различаются. Од- нако не забывайте, что IGMP-пакет версии 2 содержит поля версии и типа сообщения в одном поле, а 0x11 в двоичном исчислении — 00010001, что похоже на пакет IGMP со значением 1 в поле версии и типа.
Запрос о членстве (0x11) в версии 2 слегка отличается от такого запроса в версии 1, поскольку позволяет выяснить членство для конкретного груп- пового адреса.
Механизм таков: группе отправляется пакет запроса о членстве с конкрет- ным адресом в поле адреса. Кроме того, поле максимального времени ожи- дания позволяет задать время, в течение которого узлы должны отвечать на запрос до прекращения перенаправления им многоадресного трафика ука- занной группы.

4 1 4 ЧАСТЬ И Интерфейс прикладного программирования Winsock
Использование IP_HDRINCL
Как уже упоминалось, с простыми сокетами могут работать только некото- рые протоколы типа ICMP и IGMP Нельзя создать простой сокет при помо- щи IPPROTOJJDP и манипулировать заголовком UDP, это же относится к
TCP Для манипулирования заголовком IP, TCP или UDP (да и любого друго- го вложенного в IP протокола) необходимо использовать с простым соке- том параметр IP_HDRINCL, который позволяет сформировать собственный заголовок IP или других протоколов
Если вы хотите реализовать собственную схему протокола вложенного в IP, создайте простой сокет и используйте в качестве ссылки на протокол значение IPPROTO_RAW Это позволит самостоятельно задать поле протокола в заголовке IP и сформировать заголовок протокола В этом разделе мы по шагам рассмотрим формирование собственных пакетов UDP Разобравшись,
как манипулировать заголовком UDP, вы без труда сможете создать собствен- ные заголовки протокола и управлять другими протоколами под IP
При использовании параметра IPHDRINCL требуется самостоятельно заполнять заголовок IP для каждого вызова отправки, а также заголовки лю- бых других вложенных протоколов (см главу 9, рис 9-3) Заголовок UDP
проще Его величина всего 8 байт, при том он содержит всего четыре поля
(рис 13-4) Первые два хранят 16-битные номера портов отправителя и ад- ресата Третье поле определяет длину UDP, равную суммарной длине заголов- ка UDP и данных (в байтах) Четвертое — поле контрольной суммы, которое мы рассмотрим вкратце В конце пакета UDP размещаются данные
11Мйт*ый яорт отправителя
16-бйТнаядля«аШР
16-битная контрошш сумма UDP
Рис. 13-4. Формат заголовка UDP
Поскольку UDP — ненадежный протокол, вычисление контрольной сум- мы не обязательно, однако, для полноты картины мы рассмотрим и этот ас- пект В отличие от контрольной суммы IP, которая охватывает только заго- ловок IP, контрольная сумма UDP включает данные и часть заголовка IP До- полнительные поля, требуемые для вычисления контрольной суммы UDP,
получили название псевдозаголовка Он состоит из следующих элементов
В 32-битный IP-адрес отправителя (заголовок IP), эп
Ш 32-битный IP-адрес получателя (заголовок IP),
Ш 8-битное обнуленное поле,
• 8-битное поле протокола,
• 16-битная длина UDP
Помимо этих элементов существуют заголовок UDP и данные Метод вы- числения контрольной суммы аналогичен IP и ICMP 1б-битная комплемен- тарная сумма Если данные выражены нечетным числом, для вычисления конт-

1   ...   30   31   32   33   34   35   36   37   ...   50


написать администратору сайта