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

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


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

ГЛАВА 11 Многоадресная
3 1 7
setsockopt(s, IPPROTO_IP, IP_ADD_HEMBERSHIP, .Г-ГГ 1H
(char O&ipmr, &len);
Для выхода из группы достаточно вызвать функцию setsockopt с парамет- ром IPJDROPjMEMBERSHIP, передав ей структуру ipjnreq с теми же значени- ями, которые использовались для присоединения к группе:
setsookopt(s, IPPR0T0_IP, IP_DROP_MEMBERSHIP,
(char O&ipmr, &len);
•tt
Щ1
Пример многоадресной рассылки в IP-сети средствами Winsock 1
"Jnnq
з '•3
В листинге 11-1 приведен пример программы многоадресной рассылки,
которая присоединяется к заданной группе и затем действует как отправи- тель или получатель (в зависимости от аргументов командной строки). В
этом примере отправитель только отправляет, а получатель просто ждет в цикле входящие данные. Конечно, возможна ситуация, выходящая за рамки примера: если отправитель отправляет данные группе и также слушает дан- ные, будучи в составе этой группы, то отправленные данные вернуться к нему во входную очередь. Такой процесс называется петлей и происходит,
только когда вы ведете рассылку в IP-сети. Далее мы обсудим, как этого из- бежать.
Листинг 11-1. Пример организации многоадресной рассылки средствами '•
.енмюмпО \\
Winsock 1
II Название модуля: Mcaetwsi.c
«include
«include
«include
«include
«define MCASTADDR
«define MCASTPORT
«define BUFSIZE
«define DEFAULT COUNT
(от
екпвнА
tnl
"234.5.6.7"
25000 1024 500
BOOL bSender = FALSE,
bLoopBack = FALSE;
DWORD dwlnterface,
dwHulticastGroup,
dwCount;
short iPort;
II
II Функция: usage
// Действовать как отправитель?
// Запретить образование петли?
С.

улк
1)ю\
// Локальный интерфейс для привязки
// Многоадресная группа, к которой присоединиться'
// Количество сообщений для отправки/приема
// Номер используемого порта
см. след, стр.

318 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 11-1. (продолжение) * д j^p"
ц i .<* i*rto)
// Описание:
// Вывод информации об использовании и выход
void usage(char *progname)
printf("usage: %s -s -nrstr -p.int -i:str -1 -n:int\n",
progname);
printf(" -s Act as server (send data); otherwise\n");
printf(" receive data.\n");
printf(" -m:str Dotted decimal multicast IP addres to join\n");
pnntf(" The default group is. Xs\n", MCASTADDR);
printf(" -p:int Port number to use\n"),
printf(" The default port is: Xd\n", MCASTPORT);
printf(" -i:str Local interface to bind to; by default \n");
p n n t f C use INADDRY_ANY\n");
pnntf(" -1 Disable loopback\n");
printf(" -n:int Number of messages to send/receive\n");
ExitProcess(-i);
// Функция: ValidateArgs
// Описание: »«e->>'
// Анализ параметров командной строки и установка некоторых глобальных
// флагов в зависимости от значений
void ValidateArgs(int argc, char **argv)
int i;
dwlnterface = INADDR_ANY; ® [*
m
dwMulticastGroup = inet_addr(MCASTADDR);
2 > №
'
1
lPort = MCASTPORT;
f вЬщ
dwCount = DEFAULT_COUNT;
3
'
e b 4
for(i = 1; l < argc; i++) _ ^
if ((argv[i][0] == '-•) || (argv[i][O] == V ) )
switch (tolower(argv[i][1])) •*'
case 's' // Отправитель
bSender = TRUE;
break;
case 'm'. // Многоадресная группа
if (strlen(argv[i]) > 3)
dwMulticastGroup = inet_addr(&argv[i][3]);
J

• и«« с -«Mi Г Л А В А 11 Многоадресная рассылка
319
Листинг 11-1. (продолжение)
break; Ohi case ' i ' : // Локальный интерфейс if (strlen(argv[i]) > 3) 4т; тш юяе-н \\
dwlnterface = inet_addr(&argv[i][3]); \\
> break; ,v*lP<< .,< *)«9iA°>tt>b.L,U.i case ' p ' : // Номер порта '/ if ( s t r l e n ( a r g v [ i ] ) > 3)
pt lPort = a t o i ( & a r g v [ i ] [ 3 ] ) ;
<^ break;
case ' 1 ' : // Запретить образование петли? i*tn i bLoopBack = TRUE;
ЖИ break; et«*09 вшвдеоЗ \\
case ' n ' : // Количество сообщений для отгцмМИЦ/^рЯМЯГтя^ \\
dwCount = a t o i ( & a r g v [ i ] [ 3 ] ) ; \\
break; /Jwtaee « Шоса)) U
default: >
usage(argv[O]); 4 ,'n/ii
break;
}
return;
x
л
//
//
//
//
//
//
//
//
//
//
im
{
Функция: main
Описание:
Анализ параметров
создание сокета и
ЛЬ
командной строки, загрузка библиотеки Wmsock
i.leool
nit!) П
it®
}
присоединение к многоадресной группе. Если програци*
запущена как отправитель, то начинается отправка сообщений
группе, иначе вызывается recvfrom() для •*)
чтения сообщений,
: main(int argc, char
WSADATA
struct sockaddr_in
struct ipjnreq
SOCKET
TCHAR
int
отправленных группе. \
**argv)
ш т щ язд «»••.#»•
ч
ч*щг вав wsd; в&В«фчвгнк <
Т
ыннв,поащп
local,
remote, JW
from;
mcast;
sockM;
recvbuf[BUFSIZE],
sendbuf[BUFSIZE];
len = sizeof(struct sockaddr_in),
optval,
ret;
sit.
, Л91
{
mrox Л
W
-.введет
см. след. апр.

320 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 11-1. (продолжение)
DWORD i=0;
// Анализ командной строки и загрузка Winsock
ValidateArgs(argc, argv);
if (WSAStartup(MAKEW0RD(1, 1), &wsd) != 0)
printf("WSAStartup failed\n");
return - 1 ;
// Создание сокета. В Winsock 1 вам не потребуется никаких специальных
// флагов для указания многоадресной рассылки if ((sockM = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID.SOCKET)
printf("socket failed with: Xd\n", WSAGetLastErrorO);
WSACleanupO;
return - 1 ;
// Привязка сокета к локальному интерфейсу. Это нужно для приема данных {
local.sin_family = AF_INET; {
local.sin_port = htons(iPort);
local.sin_addr.s_addr = dwlnterface; V
if (bind(sockM, (struct sockaddr *)&local, \\
sizeof(local)) == SOCKET.ERROR) «wnO v.
{ ' ,tk \\
printffbind failed with: Xd\n", WSAGetLastErrorO); .а V
closesocket(sockM); ct \
v
WSACleanupO; 1 \
v return -1; , ,„41 •(* V
In.
1
// Настройка структуры im_req для указания группы, к которой мы }
// хотим присоединиться, и интерфейса < ATAQASW
// u Mj\ttomk9Q&
remote.sin_family = AF_INET;
remote.sin_port = htons(iPort);
remote.sin_addr.s_addr = dwMulticastGroup; f№%ajql Л*,
T?
mcast.imr_multiaddr.s_addr = dwMulticastGroup; I
mcast.imr_interface.s_addr = dwlnterface;
if (setsockopt(sockM, IPPR0TO_IP, IP_ADD_MEMBERSHIP,
(char *)&mcast, sizeof(mcast)) == SOCKET.ERROR)
printf("setsockopt(IP_ADD_MEMBERSHIP) failed: Xd\n",

Г Л А В А 11 Многоадресная рассылка
321
Чистинг 11-1. (продолжение')
WSAGetLastErrorO);
closesocket(sockM);
WSACleanupO;
return -1;
// Настройка значения TTL (по умолчанию - 1)
optval = 8;
if (setsockopt(sockM, IPPR0TO_IP, IP_MULTICAST_TTL,
(char O&optval, sizeof(int)) == SOCKET.ERROR)
printf("setsockopt(IP_MULTICAST_TTL) failed: Xd\n",
WSAGetLastErrorO);
closesocket(sockM);
WSACleanupO;
return -1;
// Запрет петли, если это было выбрано. Заметьте,
// что в Windows NT 4 и Windows 95 петлю запретить нельзя
if (bLoopBack)
optval = 0;
if (setsockopt(sockM, IPPR0T0_IP, IP_MULTICAST_LOOP,
(char *)&optval, sizeof(optval)) == S0CKET_ERROR)
printf("setsockopt(IP_MULTICAST_LOOP) failed: Xd\n",
WSAGetLastErrorO);
closesocket(sockM);
WSACleanupO;
return - 1 ;
>
10*
» ...•
, " I
m
i/
14
if (IbSender) // Клиент
// Прием порции данных f o r ( i = 0; i < dwCount;
if ((ret = recvfrom(sockM, recvbuf, BUFSIZE, 0,
(struct sockaddr *)&from, &len)) == SOCKET_ERR0R)
{
printf("recvfrom failed with: Xd\n",
WSAGetLastErrorO);
closesocket(sockM);
WSACleanupO;
см. след. стр.

3 2 2 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 11-1. (продолжение)
return - 1 ;
} и в ) : ;Э
r e c v b u f [ r e t ] = 0 ; g ^ '<(> -•*'
p r i n t f ( " R E C V :
-
Xs' from \n", recvbuf, i i n e t _ n t o a ( f r o m . s i n _ a d d r ) ) ; {
та) JTT RH««»*ine к itH \\
} }
else // Сервер ;в.
// Отправка порции данных < V14}O<&(« isda)
// J
f o r ( i = 0; i < dwCount; i++) ц
sprintf(sendbuf, "server 1: This is a t e s t : Xd", i ) ; J
if (sendto(sockM, (char *)sendbuf, strlen(sendbuf), 0, M
( s t r u c t sockaddr *)&remote, ; f - niuJei sizeof(remote)) == SOCKET_ERROR)
rV
., t, ,
;;
{
{ IW»CI o i t « u i .wvren тщпв
£ \S
p r i n t f ( " s e n d t o f a i l e d w i t h : Xd\n"ipbncW # f>
ГО вноЬоШ a OTS< \\
WSAGetLastErrorO); \\
closesocket(sockM);
t (
**.»<*} > wysw» аяя «р»#Й1#%*ВД4Лк) *'t
WSACleanupO; }
return - 1 ; ;0 » lev.t^e
} >( ' ч" ОТО"""" ' '
f qo^s f
*fc) Iri
Sleep(500); 'ta}i >Я(«
} JW ^ * ) ^
// Выход из группы if (setsockopt(sockM, IPPR0T0_IP, IP_DROP_MEMBERSHIP,
(char *)&mcast, sizeof(mcast)) == S0CKET_ERR0R)
< 4
printf("setsockopt(IP_DROP_MEMBERSHIP) f a i l e d : Xd\n", <
WSAGetLastErrorO);
closesocket(sockM);
it)
, & ^ }
WSACleanupO; ' \\
return 0; *b > i ;0
Одно предостережение при организации рассылки в Winsock 1: исполь- зуйте корректные заголовочный файл и библиотеки для компоновки. Если вы загружаете библиотеку Winsock 1.1, подключите Winsock.h и компонуй- те его с Wsock32.1ib. Для версии 2 или выше подключайте Winsock2.h и Ws2tc- pip.h и компонуйте их с Ws2_32.1ib. Это необходимо, поскольку существует два множества значений для констант IP'_ADD_MEMBERSHIP, IP_DROP_MEM-
BERSHIP, IPJWULTICASTJF и IP ^MULTICAST LOOP. Исходная спецификация значений, написанная Стивеном Дирингом (Stephen Deering), никогда офи-

" ' " Г Л А В А 11 Многоадресная рассылка 323
'циально не включалась в спецификацию Winsock. В результате они измени- лись в спецификации Winsock 2. Конечно, если вы используете раннюю вер-
С(ию Winsock, компоновка с wsock32.lib решит все проблемы и константы по- лучат корректные значения даже при запуске на компьютере с Winsock 2.
Рассылка средствами Winsock 2
Многоадресная рассылка в Winsock 2 немного сложнее, чем в Winsock 1, но поддерживает разные протоколы, что дает дополнительные возможности,
например, использовать Quality of Service (QoS). Кроме того, рассылка в
Winsock 2 позволяет применять протоколы, поддерживающие маршрутизи- руемые схемы. Параметры сокета больше не нужны для инициализации членства в группе — им на смену пришла функция WSAJoinLeaf.
SOCKET WSAJoinLeaf(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
DWORD dwFlags
);
Параметр 5 — описатель сокета, возвращенный WSASocket. Переданный сокет должен быть создан с соответствующими флагами, иначе WSAJoinLeaf
вернет ошибку WSAEINVAL. Помните о необходимости задать два флага: один показывает, будет ли этот сокет маршрутизируемым в плоскости управления,
другой — будет ли сокет маршрутизируемым в плоскости данных. Флаги для плоскости управления — WSA_FIAG_MULTIPOINT_C_ROOT и WSA_FLAG_MU-
LTIPOINT_C_LEAF. Флаги для плоскости данных - WSA_FLAG_MULTIPOINT_
D_ROOTKWSA_FLAG_MULTIPOINT_D_LEAF.
Второй параметр — структура SOCKADDR, специфичная для используемо- го протокола. Для маршрутизируемых схем управления (например, ATM)
этот адрес указывает клиента, которого нужно пригласить, а для немаршру- тизируемых схем (например, IP) — это адрес группы, к которой узел присо- единяется.
Параметр namelen — длина в байтах параметра пате. Параметр lpCaller-
Data используется для передачи буфера данных партнеру в установленном сеансе, a lpCalleeData указывает буфер, который будет передан обратно. Эти два параметра пока не реализованы на платформах Windows и должны быть равны NULL. Параметр lpSQOS задает структуру FLОWSPEC, указывающую тре- буемую пропускную способность для приложения (подробнее о QoS — в главе 12.) Параметр lpGQOS игнорируется, поскольку ни одна из платформ
Windows не поддерживает группы сокетов. Последний параметр — dwFlags,
показывает роль узла: отправка данных, прием данных, или и то, и другое.
Возможные значения —JL_SENDER_ONLYJL_RECEIVER_ONLYviJL_BOTH.

324
ЧАСТЬ II Интерфейс прикладного программирования Winsock
Функция возвращает описатель SOCKET для сокета, связанного с многот адресной группой. Если вызов WSAJoinLeaf выполнен с асинхронным (небло- кирующим) сокетом, возвращаемый описатель сокета не пригоден к исполь- зованию, пока не завершится операция присоединения. Например, в этом случае после вызова WSAAsyncSelect или WSAEventSelect описатель не будет действителен, пока исходный сокет 5 не вернет сообщение FD_CONNECT.
Сообщение FD_CONNECT генерируется только в маршрутизируемой схеме управления, в которой параметр пате задает конкретный адрес конечной точки.
В табл. 11-1 перечислены обстоятельства, при которых приложение по- лучает сообщение FD_CONNECT. Вы вправе аннулировать ожидающий вы- полнения запрос на присоединение для этих неблокирующих режимов, выз- вав closesocket на исходном сокете. Корневой узел в многоточечном сеансе может вызывать WSAJoinLeaf один или несколько раз, чтобы добавить не- сколько листовых узлов; впрочем, в каждый момент времени ожидать выпол- нения может только один запрос на многоточечное соединение.
Табл. 11-1. Действия WSAJoinLeaf
I
7
Плоскость
управления
Маршрути- зируемая
Немаршру- тизируемая s
c_root cjeaf c_root cjeaf
Имя
Адрес листа
Адрес корня

Адрес группы
Действие
Корень приглашает лист
Лист ини- циирует соединение с корнем
Невозможная комбинация
Лист присое- диняется к группе
Прием уведомления
FD CONNECT
Да
Да

Нет
Возвращение описателя сокета
Используется для уведомления FDCLOSE
и для отправки данных только этому листу
Дубликат* .тэнсп-
'ыесж..-
_ оэроп:
А1ОЧ\Т V
Дубликат 5 >ОШ <\
Как мы уже упоминали, запрос на присоединение для неблокирующих сокетов не может завершиться немедленно. Если сокет переведен в небло- кирующий режим посредством ioctlsocket и команды FIONBIO, вызов WSA-
JoinLeaf не вернет ошибку WSAEWOULDBLOCK, поскольку эта функция фак- тически выдаст сообщение об успешном запуске Заметьте, что в асинхрон- ной модели ввода-вывода единственный способ узнать об успешном запус- ке — сообщение FD_CONNECT. (Подробнее об асинхронных моделях WSA-
AsyncSelect и WSAEventSelect — в главе 8.) Блокирующие сокеты не могут уве- домить приложение об удачном или ошибочном завершении WSAJoinLeaf.
Другими словами, применять неблокирующие сокеты не стоит, поскольку нет однозначного способа определить успешно ли присоединение к груп- пе, пока сокет не будет задействован в последующих вызовах Winsock (ко- торые вернут ошибку, если присоединения не произошло).

Г Л А В А 11 Многоадресная рассылка
325
Описатель сокета, возвращенный WSAJoinLeaf, зависит от того, является ли сокет маршрутизируемым или листовым узлом. Для маршрутизируемого узла параметр пате указывает адрес конкретного листа, который приглашается в многоточечный сеанс. Чтобы c_root поддерживал членство листьев, WSA-
JoinLeaf возвращает для листа новый описатель сокета.
Новый сокет имеет те же свойства, что и корневой описатель, использо- ванный для приглашения, включая любые асинхронные события, зарегист- рированные по асинхронным моделям ввода-вывода типа WSAEventSelect и
WSAAsyncSelect. Впрочем, эти новые сокеты следует применять только для по- лучения уведомления FD_CLOSE от листа. Любые данные, которые нужно от- править многоадресным группам, должны отправляться через сокет cjroot.
Иногда вы можете отправить данные на сокет, возвращенный WSAJoinLeaf, но их получит только лист, соответствующий этому сокету (это позволяет про- токол ATM). Наконец, чтобы удалить листовой узел из многоточечного се- анса, корень просто вызывает closesocket на сокете, соответствующем этому листу.
С другой стороны, когда WSAJoinLeaf вызывается с листовым узлом, пара- метр пате задает адрес либо корневого узла, либо многоадресной группы.
В первом случае присоединение инициируется листом, что в настоящее вре- мя не поддерживает ни один протокол (спецификация ATM UNI 4.0 будет делать это). Второй пример — рассылка в IP. В любом случае описатель со- кета, возвращенный WSAJoinLeaf — это тот же описатель сокета, что был пе- редан в 5. Когда вызов WSAJoinLeaf служит для присоединения со стороны листа, корневой узел слушает входящие соединения, используя методы bind,
listen и accept/WSAAccept, как обычно на сервере. Когда приложение хочет удалить себя из многоадресного сеанса, вызывается closesocket на том соке- те, который прекращает членство (при этом также освобождаются ресурсы сокета). Табл. 11-1 резюмирует действия, выполняемые в зависимости от типа плоскости управления, и параметры, которые передаются на сокет. С
ее помощью также можно определить, возвращается ли новый описатель сокета после удачного вызова функции и получает ли приложение уведом- ление FD_CONNECT.
Допустим, приложение вызывает accept или WSAAccept, чтобы ожидать приглашения от корня, либо выполняет роль корня, чтобы ожидать запро- сы на присоединение от листьев. Тогда функция возвращает сокет, который является описателем сокета c_leaf (такой же возвращает WSAJoinLeaf). Для работы с протоколами, которые поддерживают соединения, инициирован- ные как корнем, так и листом, в качестве входного параметра для WSAJoinLeaf
Допустимо передавать слушающий сокет c_root.
После вызова WSAJoinLeaf возвращается новый описатель сокета. Этот описатель не применяется для отправки и приема данных: он просто пока- зывает, что приложение — член многоадресной группы. Для операций от- правки и приема используется исходный описатель сокета, полученный от
WSASocket и затем переданный в WSAJoinLeaf. Вызов closesocket для нового описателя прекратит членство приложения в группе. В результате вызова
closesocket на сокете c_root все связанные с ним узлы c_leaf, использующие асинхронную модель ввода-вывода, получат уведомление FD CLOSE.

326 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Пример многоадресной рассылки в IP-сети средствами Winsock 2
Листинг 11-2 содержит программу Mcastws2.c, которая иллюстрирует присо- единение и выход из многоадресной группы с помощью WSAJoinLeaf. Это из- мененный пример организации IP-рассылки средствами Winsock 1. Отличие в том, что вызовы присоединения (выхода) здесь переписаны под WSAJoinLeaf.
Листинг 11-2. Пример организации многоадресной рассылки средствами
Winsock 2
// Модуль: Mcastws2.c
//
«include
«include
«include
«include
«define MCASTADDR "234.5.6.7"
«define MCASTPORT 25000
«define BUFSIZE 1024 •*•*»,
«define DEFAULT_COUNT 500 т Г-
BOOL bSender = FALSE, // Действовать как отправитель?
bLoopBack = FALSE; // Запретить образование петли?
(
DWORD dwlnterface, // Локальный интерфейс для привязки
dwMulticastGroup, // Многоадресная группа, к которой присоединиться
dwCount; // Количество сообщений для отправки/приема
short iPort; // Номер используемого порта ^ * •-

JK'I Н О
з
II Я'' .ИНТ
// Функция: usage >мои э">
( С
1
" • ">
I/ Описание:
// Вывод информации об использовании и выход ,
//
void usage(char •progname)
{
printf("usage: Xs -s -m:str -p:int -i:str -1 -n:int\n",
j
progname);
printfC -s Act as server (send data); otherwise\n");
printfC receive data.\n");
printfC -m:str Dotted decimal multicast IP addres "
"to Join\n");
printfC The default group is: Xs\n", MCASTADDR);
printfC -p:lnt Port number to use\n");
printfC The default port is: Xd\ri", MCASTPORT);
printf(" -i:str Local interface to bind to; by default \n");

т
Г Л А В А 11 Многоадресная рассылка
327
Листинг 11 -2. (продолжение)
printfC use INADDRY_ANY\n");
printf(" -1 Disable loopback\n");
printfC -n:int Number of messages to send/receive\n"); »b
ExitProcess(-i); »j1
II
И Функция: ValidateArgs
.j»
c y
// Описание: ь ^
// Анализ параметров командной строки и у о п м м к * некоторых глобальных
// флагов в зависимости от значений \д
// 1, nie» -««дону* \\
void ValidateArgs(int argc, char **argv) \\
\\
\\
\\
\\
\\
\\
dwlnterface = INADDR_ANY; IHBH ОТ ,апвт»в»|»птс dwMulticastGroup = inet_addr(MCASTADDR);(oitv>ei iPort = MCASTPORT;
dwCount = DEFAULT_COUNT;
Яньс
tnl
for(i=1; i < argc ;:
{
if ((argv[i][O] == '-') || (argv[i][O]
{ at- switch (tolower(argv[i][i]))
{
case ' s ' : //Отправитель «Те- bSender = TRUE;
break;
ATA0A3W
ТЗЖЮ8
ЙАНЗТ
case 'пГ: // Многоадресная группа if (strlen(argv[i]) > 3)
dwMulticastGroup = inet_addr(4argv[i][3]);
break; емпанА \\
case 'i': // Локальный интерфейс \\
if (strlen(argv[i]) > 3) *<-*blfaV
dwlnterface = met_addr(4argv[i][3]);
break; "•*) Г'
case 'p': // Номер порта if (strlen(argv[i]) > 3) 1
iPort = atoi(&argv[i][3]); -I
break;
case '1': // Запретить образование петли?
bLoopBack = TRUE;
break;
case 'n': // Количество сообщений для отправки/приема
см. след. стр.

328
ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 11-2. (продолжение)
dwCount = atoi(&argv[i][3]);
break;
default:
usage(argv[O]);
break;
return;
// Функция: main
Г ч»
U i-
X^

: а зовпф
Описание:
Анализ параметров командной строки, загрузка библиотеки Winsock,
//
//
//
//
//
//
//
int main(int argc, char w
\\
w w
w w
;ov
}
fr>r создание сокета и присоединение многоадресной группе. Если программа
запущена как отправитель, то начинается отправка сообщений >ostTe?nlwb группе, иначе вызывается recvfromO для i l H
чтения сообщений, отправленных группе. 'АОМ
1 »
**argv)
x wsd; }
local,
p
I
1
!
remote, "HV я from;
sock, sockM;
recvbuf[BUFSIZE], табэ sendbuf[BUFSIZE];
len = sizeof(struct sockaddr_in),
optval,
ret;
i=0;
WSADATA
struct sookaddr_in
SOCKET
TCHAR
int
DWORD
// Анализ командной строки и загрузка Winsock
//
ValidateArgs(argc, argv);
if (WSAStartup(MAKEW0RD(2, 2), &wsd) != 0)
{
printf("WSAStartup() failed\n");
return -1;
>
// Создание сокета. В Winsock 2 нужно задать многоадресные
// свойства, с которыми будет использоваться сокет
//
if ((sock = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0,
WSA_FLAG_MULTIPOINT_C_LEAF

Г Л А В А 11 Многоадресная рассылка 329
аа
Листинг 11-2. (продолжение)
| WSA_FLAG_MULTIPOINT_D_LEAF
| WSA_FLAG_OVERLAPPED)) == INVALID.SOCKET)
printf("socket failed with: Xd\n", WSAGetLastErrorO); '
WSACleanupO;
return -1; {
} <
// Привязка сокета к локальному интерфейсу. Это ну«ЙО для приеМИЗДОМйЯ \\
local.sin_family = AF_INET; > Я", лвпон «i \\
local.sin_port = htons(iPort); XTfti «is вд-ij* \\
local.sin_addr.s_addr = dwlnterface; f «n -'*a oTooq.i u8 \\
\ \
if (bind(sock, ( s t r u c t sockaddr *)&local, * « НЯоов)) ti sizeof ( l o c a l ) ) == SOCKET.ERROR) sJte
{ -Л- p r i n t f ( " b i n d f a i l e d w i t h : Xd\n", WSAGetLastErrorO)- >
closesocket(sock); "iq
WSACleanupO;
£o return - 1 ; *0A3H
} этикет
// Настройка структуры SOCKADDR_IN, описывающей многоадресную {
// группу, к которой мы хотим присоединиться
// Yiioi ibneSdi) il remote.sin_family = AF_INET; i
remote.sin_port = htons(iPort); V\
remote.sin_addr.s_addr = dwMulticastGroup; l\
// i i *
// Настройка значения TTL
optval = 8;
if (setsockopt(sock, IPPROTO.IP, IP_MULTICAST_TTL,
4


(char *)&optval, sizeof(int)) == SOCKET ERROR)
{ ,«
printf("setsockopt(IP_MULTICAST_TTL) failed: Xd\n",
WSAGetLastErrorO);
closesocket(sock);
WSACleanupO;
return -1;
}
// Запрет петли, если это было выбрано
//
if (bLoopBack)
{
optval = 0;
if (setsockopt(sock, IPPROTO.IP, IP_MULTICAST_LOOP,
(char *)4optval, sizeof(optval)) == SOCKET.ERROR)
{
см. след. стр.

3 3 0 ЧАСТЬ II Интерфейс прикладного программирования Winsocfc
Листинг 11 -2. (продолжение)
(
printf("setsockopt(IP_MULTICAST_LOOP) failed: Xd\n",r>w j
WSAGetLastErrorO);
closesocket(sock); у
WSACleanupO; ^
return - 1 ;
4
gtf
} si
> {
// Присоединение к многоадресной группе. Заметьте: sockM ,цф у,
// не используется для отправки или получения данных. Он использует§^
£
воо1
// когда мы хотим выйти из многоадресной группы. Л з з д !
// Вы просто вызываете на нем closesocket().
if ((sockM = WSAJoinLeaf(sock, (SOCKADDR *)&remote,
sizeof(remote), NULL, NULL, NULL, NULL,
JL_BOTH)) == INVALID.SOCKET) j printf("WSAJoinLeaf() f a i l e d : Xd\n", WSAGetLastErrorO); ^
closesocket(sock); /gjj
1
WSACleanupO; _,
J r T
return - 1 ;
5
-
\\
\\
if (IbSender) // Получатель \\
// Прием порции данных
for(i = 0; i < dwCount; i++) \\.
t n, 4)jfta
if ((ret = recvfrom(sock, recvbuf, BUFSIZE, 0, \д
(struct sockaddr *)&from, ilen)) == SOCKET_ERROR)
{ ;6 * levjqo
printf("recvfrom failed with: Xd\n", >too*Je-») 11
WSAGetLastErrorO); ,» i»Ho)
closesocket(sockM); j
closesocket(sock); .
: i
q
WSACleanupO;
return -1;
recvbuf[ret] = 0;
printf("RECV:
-
Xs' from \n", recvbuf, {
inet_ntoa(from.sin_addr)); »jn»6 \N
> \\
> Ш) ft
else // Отправитель }
// Отправка порции данных
for(i = 0; i < dwCount;

1   ...   25   26   27   28   29   30   31   32   ...   50


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