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

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


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

ГЛАВА 11 Многоадресная
331
Листинг 11-2. (продолжение)
sprintf(sendbuf, "server 1: This is a test: Xd", i ) ;
if (sendto(sock, (char *)sendbuf, strlen(sendbuf), 0,
(struct sockaddr *)&remote,
sizeof(remote)) == SOCKET_ERROR)
.8-ГГ
Jioqqo3" «Aulont printf("sendto failed with
WSAGetLastErrorO);
closesocket(sockM);
closesocket(sock);
WSACleanupO;
return - 1 ;
> -tv
Sleep(500); • "
: Xd\n",
»sor
«littb*
)
// Выход из группы путем закрытия sock. При использовании ч»с0ь>--Qvrt»
// немаршрутизируемых плоскостей управления и данных WSAJoinLeaf Т Э У »й(1
// возвращает тот же описатель сокета, который вы ей передали. t>Mlex>ld
0B0W0
J008
closesocket(sock);
WSACleanupO;
return -1;
С Г
КГ,
ге
г
JO3
Пример многоадресной рассылки в ATM-сети средствами Winsock 2
Листинг 11-3 содержит программу Mcastatm.c — простой пример многоад- ресной рассылки в сети ATM, иллюстрирующий присоединение со стороны корня. Листинг не включает файл Support.c, который инициирует некоторые процедуры, используемые в примере, но не специфичные для многоадрес- ной рассылки (например, GetATMAddress, которая просто возвращает АТМ- адрес локального интерфейса).
Вы увидите, что самая важная часть многоадресного корня — функция
Server, которая использует цикл для вызова WSAJomLeqf'для каждого клиен- та, указанного в командной строке. Сервер хранит массив сокетов для каж- дого присоединяемого клиента, однако в вызовах WSASend используется главный сокет. Если бы протокол ATM поддерживал эту возможность, сервер мог слушать на листовом сокете (например, на сокете, возвращенном WSA-
JoinLeaf), чтобы получать его «переписку». Другими словами, если клиент отправляет данные на связанном сокете, сервер получает их на соответст- вующем описателе, возвращенном WSAJoinLeaf. Остальные клиенты не полу- чат эти данные.
Посмотрите на функцию Client. Ее единственное требование к клиенту —
создать привязку к локальному интерфейсу и ожидать приглашения от сер- вера в вызове accept или WSAAccept. После приема приглашения можно ис- пользовать новый сокет для получения данных от корня.

332 ЧАСТЬ II Интерфейс прикладного программирования Winsqg)|c
Листинг 11 -3. Пример многоадресной рассылки в сети ATM t) .S-r r
// Модуль: Mcastatm.c
«include "Support.h"
«include
«include
• t f n J h q a
'tee) U
зШ tinea" )tjn.hq
«define BUFSIZE
«define MAX_ATM_LEAF
«define ATM_PORT_OFFSET
«define MAX_ATM_STR_LEN
1024
4
((ATM_ADDR_SIZE * 2) - 2)
(ATM_ADDR^SIZE * 2)
DWORD dwAddrCount = 0,
dwDataCount = 20;
BOOL bServer = FALSE,
bLocalAddress = FALSE;
char szLeafAddresses[MAX_ATM_LEAF][MAX_ATH_STR_LEN + 1],
szLocalAddress[MAX_ATM_STR_LEN + 1 ] ,
szPort[3];
SOCKET sLeafSock[MAX_ATM_LEAF];
// Модуль: usage
//
// Описание:
// Вывод информации об использовании
//
void usage(char *progname)
{
prlntf("usage: Xs [-s]\n", prognarae);
\\
С Л О Н М
J
' l 1И1ТГЭН'
Щ 1
printfC
printf("
printf("
printfC
prlntf("
printf("
-s
-l:str
-i:str
-p:xx
-n:int
ExitProcessd);
Act as root\n");
Leaf address to invite (38 chars)\n");
May be specified multiple times\n");
Local interface to bind to (38 chars)\n");
Port number (2 hex chars)\n");
Number of packets to send\n");
i О01.Ц
vvГУЛ
нас:
// Модуль: ValidateArgs
//
// Описание:
// Анализ параметров командной строки
//
void ValidateArgs(int argc, char **argv)
{
i int i;
я.
sqnro jiior/я
• re тьн
оэ

Г Л А В А 11 Мн
333
Листинг 11-3. (продолжение)
memset(szLeafAddresses, О,
MAX_ATM_LEAF * (HAX_ATM_STR_LEN + 1 ) ) ;
memset(szPort, 0, sizeof(szPort));
for(i = 1; i < argc;
if ((argv[i][O] == •-') || (argv[iJ[O] == 7'))
switch (tolower(argv[i][1]))
case 's': // Сервер
bServer = TRUE;
break;
case "1": // Адрес листа
if (strlen(argv[i]) > 3)
\\
us*qn TeyqNMqo* \\
"МЩВ ЙОЫОТЭИП \\
«jan яынонмдвоо \\
,« IiJW03)i»vie8 btov
i SW
wb
I *
strncpy(szLeafAddresses[dwAddrCount++],
&argv[i][3], MAX_ATM_8TR_LEN - 2);
break;
case
- i ' : // Локальный интерфейс wftRi. Mueqen if ( s t r l e n ( a r g v [ i ] ) > 3)
{ ^ V O
strncpy(szLocalAddress, & a r g v [ i ] [ 3 ] / a
MAX_ATM_STR_LEN - 2); '
bLocalAddress = TRUE; - вя .
4UflA8W
isrto
Jni
он «no3 \\
\\
I t
{
esie
JCTA
break;
case ' p ' : // Адрес порта if ( s t r l e n ( a r g v [ i ] ) > 3)
strncpy(szPort, & a r g v [ i ] [ 3 ] , 2);
break; \4
case ' n ' : // Количество пакетов для отправки щйонбгяЧ \\
if ( s t r l e n ( a r g v [ i ] ) > 3) \\
dwDataCount = a t o i ( & a r g v [ i ] [ 3 ] ) ; • joinJe*)Ho«
break; \\
d e f a u l t : лотЪ \\
usage(argv[O]); \
x break; ?e<
}
return;
см. след. стр.

334 ЧАСТЬ II Интерфейс прикладного п
Листинг 11-3. (продолжение) rt«u(%KW*MKWfWt4K) ,6* ft""
// Функция
1
Server
Ц Описание: „Р
// Формирует привязку к локальному интерфейсу, а затем приглашает каждый;»?
// листовой адрес, указанный в командной строке. После установки
// соединения передает порцию данных. .э|рв > i Л
ш
I) >о*
II *>
void Server(SOCKET s, WSAPROTOCOL_INFO -lpSocketProtocol) [OJUlvftia)) M
{ - I
II Процедура сервера •tlo)) rtoJhra
// )
SOCKADDR_ATM atmleaf, atmroot; :
WSABUF wsasend;
char sendbuf[BUFSIZE],
szAddr[BUFSIZE]; •••ISA \\ .'I'eeeo
DWORD dwBytesSent, >) tJ
dwAddrLen = BUFSIZE, j dwNumlnterfaces, •
1;
int ret; (
v
// Если не был указан определенный локальный интерфейс,
// выбирает первый найденный ;'f вяво
// L-.fe) tl memset(&atmroot, 0, sizeof(SOCKADDR_ATM)); }
if (! bLocalAddress)
{
dwNumlnterfaces = GetNumATMInterfaces(s);
GetATMAddress(s, 0, iatmroot.satm_number); {
}
else i s
AtoH(&atmroot.satm_number.Addr[O], szLocalAddress,
ATM_ADDR_SIZE - 1 ) ;
//
// Установка номера порта в адресной структуре
//
AtoH(&atmroot.satm_number.Addr[ATM_ADDR_SIZE-1], szPort, 1);
//
// Заполнение оставшейся части структуры SOCKADDR_ATM
//
atmroot.satm_family = AF_ATM;
atmroot.satm_number.AddressType = ATM_NSAP;
atmroot.satm_number.NumofDigits = ATM_ADDR_SIZE;
atmroot.satm_blli.Layer2Protocol = SAP_FIELD_ANY;
atmroot.satm_blli.Layer3Protocol = SAP_FIELD_ABSENT;
atmroot.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;
//
// Вывод на экран сведений о привязке и сама привязка

ГЛАВА 11 MHonamniiWniftacotttrt 4 8 5
Листинг 11-3. (продолжение) **©(кх\ > £

fl"WHT3t
if (WSAAddressToString((LPS0CKADDR)4atmroot,
,*Шл№* >fc sizeof(atmroot), lpSocketProtocol, szAddr, i J * JJU/ Л
AdwAddrLen))
printf("WSAAddressToString f a i l e d : Xd\n", B*Ji»iolA8W')
WSAGetLastErrorO); ,,,
}
printf("Binding t o : \n", szAddr);
t
if (bind(s, (SOCKADDR *)&atmroot, i sizeof(SOCKADDR_ATM)) == SOCKET.ERROR) <ж*н МТА TO«m><»f, :*TdT«wfiE \\
{ ASM soeaa ROTeee^eaee И".оЛ \S
p r i n t f ( " b i n d ( ) f a i l e d : Xd\n", WSAGetLastBrne^W^ «*• Jneгмов^т.и \\
return; л тадвмчп хиннад влмсргго \\
> \\
// Приглашение каждого листа ",вПЙ1Я#* Jieje v «A »
// П),
f o r ( i = 0; i < dwAddrCount; i++)
{
\\
\\
// Заполнение структуры SOCKADDR_ATM для каждого листа \\
//
memset(&atmleaf, 0, sizeof(SOCKADDR_ATM));
AtoH(&atmleaf.satm_number.Addr[0], szLeafAddresses[i]fb > t ;0 •
ATM_ADDR_SIZE - 1);
AtoH(&atmleaf.satm_number.Addr[ATM_ADDR_SIZE - 1 ] , Udbflee)teawi»
szPort, 1); ЬгэЗАгм « ten atmleaf.satm_family = AF_ATM; «» »» l e i )
atmleaf.satm_number.AddressType = ATM_NSAP;
atmleaf.satm_number.Numof Digits = ATM_ADDR_SIZE; ' ) w m atmleaf. satm_blli.Layer2Protocol = SAP_FIELD_ANY; >l«aid atmleaf.satm_blli.Layer3Protocol = SAP_FIELD_ABSENT;
atmleaf.satm.bhli.HighLayerlnfoType = SAP_FIELD_ABSENT; ]
И
// Вывод на экран клиентского адреса и его приглашение if (WSAAddressToString((LPSOCKADDR)&atmleaf, пЬЬШЬ > к ;0
sizeof(atmleaf), lpSocketProtocol, szAddr, fr»eJa)J*>laoeeeoIo
&dwAddrLen)) fl printf("WSAAddressToString f a i l e d : Xd\n", i
WSAGetLastErrorO); \\
p r i n t f ( " [ X 0 2 d ] I n v i t i n g ' \n", i, szAddr);
if ((sLeafSock[i] = WSAJoinLeaf(s,
см. след. стр.

3 3 6 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 11-3. (продолжение)
(SOCKADOR -O&atmleaf, sizeof(SOCKADOR_ATH), NULL, eibbAA3W)
NULL, NULL, NULL, JL_SENDER_ONLY))
== INVALID_SOCKET)
printf("WSAJoinLeaf() failed: Xd\n",
WSAGetLastErrorO);
WSACleanupO;
return;
> bnW) t i
// Заметьте: протокол ATM немного отличается от TCP. „%te
II Когда завершается вызов WSAJoinLeaf, }
II пользователь еще не обязательно принял соединение, поэтому немедмциая
// отправка данных приведет к ошибке; так что ждем некоторое время,л »t prlntf("Press a key to s t a r t sending."); иа«в1ПЖ|П \\
getchar(); \\
p r i n t f ( " \ n " ) ; „ vb > t ;0
// Отправка порции данных групповому адресу, которая
// будет реплицирована всем клиентам wsasend.buf = sendbuf; \\
wsasend.len = 128;
и
Я0
f o r ( i = 0; i < dwOataCount; i++)
{ «OQAJfTA
memset(sendbuf,
- a ' + (i X 26), 128);
ret = WSASend(s, &wsasend, 1, &dwBytesSent, 0, NULL,
NULL);
if ( r e t == SOCKET,ERROR) j
S 8
•>.-„[
{ le.t> . *te printf("WSASend() f a i l e d : Xd\n", WSAGetLastError())j s
-
М Л
break; tee "ute p r i n t f ( " [ X 0 2 d ] Wrote: Xd bytes\n", i, dwBytesSent); teelejs
Sleep(500); \\
w f o r ( i = 0; i < dwAddrCount; i++) 4A8W) 11
closesocket(sLeafSock[i]); ^xie return; »,
W
ba
> >
//
// Функция: Client i {
/ / ' •
// Описание:
// Сначала клиент привязывается к локальному интерфейсу
// (указанному в командной строке или к первому локальному АТМ-адресу).

ГЛАВА 11 Многоадресная расЛЙМ*
«87
Листинг 11-3. {продолжение) .$-14
// Затем он ожидает приема приглашения, после чего ждет приема М
//
void Client(SOCKET s, WSAPROTOCOL_INFO olpSooketProtocol)
SOCKET
SOCKADDRJVTM
DWORD
WSABUF
char int si;
atm_leaf, ,Хл4^
4
atm_root;
dwNumlnterfaces,
dwBytesRead, sJJeOApW
dwAddrLen=BUFSIZE,
dwFlags,
wsarecv;
recvbuf[BUFSIZE],
szAddr[BUFSIZE];
iLen = sizeof(SOCKADDR_ATM),
ret;
u s * . * . 1 ,i
03 <
9 -.
"л/ЬХ ;ЬвШт (5i>fid")TrJnnq
П!ЛЭ1
•02 GIJAVMl =
f ftX \ tAiSB
« i a »
^ .'(0
t i
}
{
в f
Г
i l l
\ \
\ \
w
// Настройка локального интерфейса
II
memset(&atm_leaf, 0, sizeof(SOCKADDR_ATM));
if (IbLocalAddress)
dwNumlnterfaces = GetNumATMInterfaces(s);
GetATMAddress(s, 0, &atm_leaf.satm_number);
}
else
К
таа в towle3©fl")TjnJttq вд «Htfqon ne«qft \\
\\
091 * tud vaeisew
«to > 1 ;0 »
AtoH(&atm_leaf.satm_number.Addr[O], szLocalAddress,
ATM_ADDR_SIZE-1); ;0 -
AtoH(&atm_leaf.satm_number.Addr[ATM_ADDR_SIZE - 1], « i szPort, 1);
// Заполнение структуры SOCKADDR_ATM n} ti
// *
atm_leaf.satm_family = AF_ATM;
atm.leaf,satm_number.AddressType = ATM_NSAP;
atm_leaf.satm_number.NumofDigits = ATM_ADDR_SIZE;
atm_leaf.satm_bHi-Layer2Protocol = SAP_FIELD_ANY; :
atm_leaf.satm_blli.Layer3Protocol = SAP_FIELD_ABSENT;
atm_leaf.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;
// я
// Вывод на экран адреса, к которому мы привязываемся, и сама привязка
//
if (WSAAddressToString((LPSOCKADDR)&atm_leaf,
sizeof(atm_leaf), lpSocketProtocol, szAddr,
&dwAddrLen))
см. след. стр.

338
ЧАСТЬ II Интерфейс прикладного Программирами 1ия Winsock
Листинг 11 -3. (продолжение)
pnntfC'WSAAddressToString failed: Xd\n",
WSAGetLastErrorO);
>
printfC Binding to- <)fs>\n", szAddr),
if (bind(s, (SOCKADDR *)&atm_leaf, sizeof(SOCKADDR_ATH))
== SOCKET_ERROR)
pnntf("bind() failed: Xd\n", WSAGetLastErrorO);
return;
listen(s, 1);
// Ожидание приглашения
Л-tttHHr ъ;П,
НО *№ТвВ \
s
ТЗЗШ:
JWOAXOO?
ш
16
memset(&atm_root, 0, sizeof(SOCKADDR_ATM)),
if ((si = WSAAccept(s, (SOCKADDR *)&atm_root, iiLen, NULL* »jJt
0)) == INVALID_SOCKET) jsn
pnntf("WSAAccept() failed Xd\n", WSAGetLastError()){.j(OR
return;
printf("Received a connection'\n'); rgibi
// Прием порции данных вт
wsarecv.buf = recvbuf,
for(i = 0, l < dwDataCount;
W

dwFlags = 0;
wsarecv.len = BUFSIZE; ?}g ret = WSARecv(sl, iwsarecv, 1, AdwBytesRead, AdwFlags, 4sa
NULL, NULL); V\
if (ret == S0CKET_ERR0R) e»raC W
{ \^
pnntf("WSARecv() failed: Xd\n", WSAGetLastErrorO); tee! mJ3
break, t»eI_e>J«>
if (dwBytesRead == 0)
break,
recvbuf[dwBytesRead] = 0;
printfC [X02d] READ Xd bytes: 'Xs
-
\n", i, dwBytesRead, \\
recvbuf); ь т доа*В \\
}
closesocket(sl),
return;

ГЛАВА 11 Многоадресная
339
\м\ц\\
тшт*
Листинг 11-3. (продолжение)
II Функция: mam
II
Ц Описание
// Эта функция загружает библиотеку Winsock, анализирует параметры
// командной строки, создает соответствующий сокет (с правильными
// корневыми или листовыми флагами) и запускает функции клиента или сервера
// в зависимости от заданных флагов.
int main(int argc, char **argv) {
) к
WSADATA
SOCKET
WSAPROTOCOL_INFO
DWORD
wsd;
s;
lpSocketProtocol;
dwFlags;
n
r
,
JK
it
(f!
"V* %
• lie
t
ValidateArgs(argc, argv);
//
// Загрузка библиотеки Winsock
//
if (WSAStartup(MAKEW0RD(2, 2), &wsd) i= 0)
{
printf("WSAStartup failed\n");
return - 1 ;
}
// Поиск ATM-совместимого протокола
//
if (FindProtocoK&lpSocketProtocol) == FALSE)
{
printf("Unable to find ATM protocol entryi\n");
return -1;
}
// Создание сокета с соответствующими корневыми или листовыми флагами
//
if (bServer)
dwFlags = WSA_FLAG_OVERLAPPED
| WSA_FLAG_MULTIPOINT_C_ROOT
I WSA_FLAG_MULTIPOINT_D_ROOT;
else dwFlags = WSA_FLAG_OVERLAPPED
I WSA_FLAG_MULTIPOINT_C_LEAF
I WSA_FLAG_MULTIPOINT_D_LEAF;
If ((s = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &lpSocketProtocol, 0,
dwFlags)) == INVALID_SOCKET)
pnntf("socket failed with. Xd\n", WSAGetLastErrorO);
WSACleanupO;
см. след. стр.

3 4 0 ЧАСТЬ II Интерфейс прикладного Нрограк
Листинг 11 -3. {продолжение)
return - 1 ,
// Запуск соответствующего драйвера в зависимости от флагов, эмнюшь
// которые были заданы в командной строке 5
if (bServer)
Server(s,
else
Client(s,
closesocket(s)
WSACleanupO,
return 0,
>
SlpSocketProtocol);
&1pSocket P rotocol);
ATAP
П
:Ioo*tof J03&W
Общие параметры Winsock
Три параметра сокета применяются в обеих реализациях Winsock IP_MUL-
TICASTJTL, IP_MULTICAST_IF и IPJWULTICASTJLOOP Их обычно ассоцииру- ют с параметрами Winsock 1 для присоединения и выхода из многоадрес- ных групп, однако они могут в равной степени использоваться и в Winsock
2 Естественно, все три параметра относятся только к 1Р-рассылке
Параметр IP_MULTICAST_TTL
Задает значение TTL для данных рассылки По умолчанию TTL равно 1, то есть данные отбрасываются первым же маршрутизатором и доставляются лишь по своей сети Если вы увеличите TTL, данные смогут пересечь столько маршрутизаторов, сколько указано в TTL Маршрутизатор не пересылает дей- таграммы с адресами назначения в диапазоне 224 0 0 0 — 224 0 0 255, неза- висимо от значения TTL Эта область адресов зарезервирована для протоко- лов маршрутизации и других низкоуровневых протоколов изучения топо- логии, а также служебных протоколов — типа поиска шлюзов и сообщения о членстве в группе
Когда вы вызываете setsockopt, параметр level должен быть равен IPPROTOJP,
optname IP_MULTICASTjTTL, a optval — содержать целое число, задающее зна- чение TTL Следующий фрагмент иллюстрирует настройку TTL
int optval, 5 ^
optval = 8,
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&optval,
sizeof(mt)) == SOCKET_ERROR) >
<
// Ошибка

ГЛАВА 11 Многоадресная рассылка 341
Помимо этого параметра можно использовать SIO_MULTICAST_SCOPE с
функцией WSAIoctl или toctlsocket
Параметр TTL не обязателен для многоадресной рассылки в ATM, так как отправка данных через ATM производится в одном направлении и все полу- чатели известны Поскольку плоскость управления — маршрутизируемая,
узел c_root должен явно приглашать каждый лист Так что вам не нужно ограничивать область передачи данных — данные не будут дублироваться в сетях, где может не оказаться участников многоадресной рассылки
1   ...   26   27   28   29   30   31   32   33   ...   50


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