Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование в сетях Windows

.pdf
Скачиваний:
538
Добавлен:
11.03.2015
Размер:
3.02 Mб
Скачать

388

ЧАСТЬ II

Интерфейс прикладного программирования Winsock

 

 

 

 

 

 

 

Листинг 12-1.

(продолжение)

 

 

 

 

 

printf("FD_WRITEn");

ШОА.С

 

 

 

if (ne.lNetworkEvents & FtyMD '

 

 

 

 

pnntf("FD_QOS\n");

 

 

 

 

return;

 

 

 

 

 

 

// Функция: Client

 

st

 

 

 

 

 

 

 

 

// Описание:

 

 

 

 

 

 

//

Подпрограмма

клиента инициирует

соединение,

задает QOf в нужны! момент

//

времени и

обрабатывает

входящие

события.

f'Ч

 

 

 

 

 

 

 

void

Client(SOCKET

s)

 

 

 

 

{

 

server,

 

 

 

 

 

SOCKADDR_IN

 

 

 

 

 

 

local;

;()tfievls

 

 

 

 

WSABUF

wbuf;

 

 

 

 

 

DWORD

dwBytes,

 

 

 

 

 

 

dwBytesSent,

 

 

 

 

 

 

dwBytesRecv,

 

 

 

 

 

 

dwFlags;

 

 

 

 

 

HANDLE

hEvent;

 

 

.

,i-

 

int

ret, i;

 

,j,.

 

 

char

databuf[DATA_BUFFER_SZ];

ТЗЖ»

ti

 

QOS

*lpqos;

 

 

 

 

 

WSANETWORKEVENTS ne;

 

 

Ш о о 1 А Г

 

hEvent = WSACreateEvent();

 

 

Him,

 

 

 

 

if (hEvent === NULL)

printf("WSACreateEvent() failed: Xd\n", WSAGetLastErrorfJ}; return;

lpqos = NULL;

if (iSetQos == SET_Q0S_BEF0RE)

local.sin_family = AF_INET;

j«l

local.sin_port = htons(O);

ve

local.sin_addr.s_addr = htonl(INADDR_ANY);

 

t Tt

if (bind(s, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR)

printf("bind() failed: Xd\n", WSAGetLastErrorO); return;

ГЛАВА 12 Качество обслуживания ,

389

Листинг 12-1.

(продолжение)

*>,

ret = WSAIoctl(s, SIO_SET_QOS, iclientQos, sizeof(clientQos), NULL, 0, &dwBytes, NULL, NULL);

 

if (ret == SOCKET_ERROR)

 

и

 

printf("WSAIoctl(SIO_SET_QOS)

failed:

Xd\n",

 

WSAGetLastErrorO);

и

дт/

 

return;

'

ff-2

>

 

 

 

e l s e

if (iSetQos == SET_QOS_DURING)

 

 

 

lpqos = &clientQos;

 

 

e l s e

if (iSetQos == SET_QOS_EVENT)

 

 

{

clientQos.SendingFlowspec.ServiceType |= SERVICE_NO_Q0S_SIGNALING;

clientQos.ReceivingFlowspec.ServiceType |= SERVICE_NO_QOS_SIGNALING;

1HNT УШ

fud

\Q

"feft

( Г )

. j ^

»,

) It

}

;пЬц

J

ret = WSAIoctl(s, SI0_SET_Q0S, &clientQos,

 

sizeof(clientQos), NULL, 0, idwBytes, NULL,

NULL); ,AStt * Jet

if (ret == S0CKET_ERR0R)

U,»,%J%i) It

printf("WSAIoctl() failed: Xd\n", WSAGetLastErrorO)»nbq

return;

 

server.sin_family = AF_INET;

Ti

}

server.sin_port = htons(5150);

 

server.sin_addr.s_addr = inet_addr(szServerAddr);

'nitq

printf("Connecting to: Xs\n", lnet_ntoa(server.sin_addr));

ret = WSAConnect(s, (SOCKADDR *)4server, sizeof(server), NULL, NULL, lpqos, NULL);

if (ret == S0CKET_ERR0R)

printf("WSAConnect() failed: Xd\n", WSAGetLastErrorO)! ми

return;

зэт) Itt

 

т t i - '\

ret = WSAEventSelect(s, hEvent, F0_READ

FD_WRITE

FD_CLOSE | FD_Q0S);

 

if (ret == S0CKET.ERR0R)

 

printf("WSAEventSelect() f a i l e d : Xd\n", WSAGetLastErrorO);

см. след. стр.

390 ЧАСТЬ II Интерфейс прикладного программирования Winsock

Листинг 12-1.

(продолжение)

\.~>

 

 

 

 

 

 

return;

 

 

 

 

 

 

 

 

 

 

}

 

 

 

ttiii ,800.1

 

 

 

 

 

 

 

 

 

 

 

ФЙ ,0 ,J.Win

 

 

 

 

 

 

wbuf.buf

=

databuf;

 

 

 

.'

 

 

 

wbuf.len

=

DATA_BUFFER_SZ;

 

 

 

 

 

 

 

 

 

 

 

 

3O0_T3CJ!

 

 

 

^

 

 

memset(databuf, '#', DATA_BUFFER_SZ);

 

КГ

Пш»,1

 

 

databuf[DATA BUFFER_SZ-1] = 0;

 

 

 

 

 

/

 

 

 

 

 

 

 

 

 

Г

 

<

 

while (1)

 

 

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

"iKI

 

eo0?u3

ret

= WSAWaitForMultipleEventsd, ShEvent,

FALSE,

»ila* •

sop<>f

 

 

WSA_INFINITE, FALSE);

 

 

 

 

 

 

 

if (ret == WSA_WAIT_FAILED)

 

 

 

 

 

 

 

 

printf("WSAWaitForMultipleEventsO failed: Xd\n",iS)_30IVR33

 

 

 

 

WSAGetLastErrorO);

«-

 

 

 

 

 

 

 

return;

 

 

;

 

 

 

IVR38

 

ret = WSAEnumNetworkEvents(s,

hEvent, &ne);

 

,0ТПч

 

 

 

if (ret == SOCKET_ERROR)

 

 

 

 

> .ТЗЛ

•• tei) ft

 

printf("WSAEnumNetworkEvents() failed:

Xd\n",*oIA8«'')tJnii(}

 

 

 

 

WSAGetLastErrorO);

 

 

 

 

 

;tnut*i

 

 

return;

 

 

 

 

 

 

 

 

 

if (ne.lNetworkEvents & FD_READ)

 

 

 

 

 

 

{

 

 

 

 

 

 

-ТЭИ13А *

yJleet.nits.i»vi9c'

 

 

lf (ne.iErrorCode[FD_READ_BIT])

 

rri>enoJrt

 

 

 

 

 

printf("FD_READ error:

Xd\n",

'£ »

ibca_

 

 

 

 

 

 

ne.iErrorCode[FD_READ_BIT]);

 

 

 

 

 

 

 

else

 

 

 

 

 

 

 

 

 

 

 

printf("FD_READ\n");

 

 

 

 

 

 

 

 

wbuf.len

=

4096;

 

 

 

 

 

UtW

.JJl'H

 

dwFlags

= 0;

 

 

 

 

 

'02

»* Зет

 

ret = WSARecv(s, &wbuf, 1,

idwBytesRecv,

&dwFlags,

 

'>

 

 

 

NULL,

NULL);

 

 

 

 

 

4

 

 

if

(ret

==

SOCKET.ERROR)

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

<

<

 

 

 

 

printf("WSAReov() failed: Xd\n",

 

 

 

 

 

 

 

 

 

WSAGetLastErrorO);

 

 

 

 

 

 

 

 

return;

 

 

 

 

 

 

 

)

 

 

 

 

 

 

 

Л

 

 

 

printf("Read: Xd bytes\n",

dwBytesRecv);

 

 

<i)

tl

 

wbuf.len

=

dwBytesRecv;

 

 

 

 

 

 

 

 

ret = WSASend(s, &wbuf, 1,

&dwBytesSent,

0,

NULL,

 

 

 

ГДАВА12

Листинг 12-1.

{продолжение')

 

 

шЫхтук)

. M l 1и*г>зд>

 

NULL);

 

 

 

 

v, -;,

 

 

 

 

}

if (ret == SOCKET.ERROR)

эа •

 

|31,«г)П

 

 

printf("WSASend()

failed:

 

 

 

 

 

 

 

WSAGetLastErrorO);

 

 

 

 

 

 

 

return;

 

 

 

 

 

3iOJL'

 

 

щ

 

printf("Sent:

%d bytes\n",

dwBytesSent)! sv

 

 

 

< w

if (ne.lNetworkEvents &

FD.WRITE)

 

 

 

 

 

{

 

 

 

 

 

 

 

 

2 t

 

lie*.'

»ni

if (ne.iErrorCode[FD_WRITE_BIT])

 

 

 

 

 

 

printf("FD_WRITE

error:

Xd\n",

CO

 

 

t*rta

 

 

ne.iErrorCode[FD_WRITE_BIT]);

a<v,.>

 

800

else

 

 

 

 

 

 

$Jv0wb

 

QfiOV^C

 

printf("FD_WRITE\n");

) я > . v<.3ffv3»Rd

 

J0O8

if

(! bWaitToSend)

 

 

,а„800.fl4]etrJ3icn3l .<Wi)

I!

 

wbuf.buf

=

databuf;

>t

> S<

')f3

 

 

wbuf.len = DATA_BUFFER_SZ;

 

 

 

 

 

 

//

Если

сеть

не

может

обеспечить

пропускную

способность,

 

//

не отправлять

данные.

 

 

 

 

{

 

//

 

 

 

 

 

 

 

в

 

 

 

 

if

(!AbleToSend(s))

 

 

 

*?„,

 

 

 

 

printf("Network is unable to provide " }) к aopqf

 

 

 

"sufficient best-effort bandwidth\n"jj»j( n з$г

 

 

printf("before the

reservation

"

 

jd

 

 

 

 

 

"request

is approved\n");

 

 

«

jei)

U

1

>

 

 

 

 

 

 

 

}

 

 

 

 

for(i = 0 ;

i < 1; i++)

 

 

 

 

 

 

 

 

ret = WSASend(s, &wbuf, 1, idwBytesSent, 0,

 

{

 

 

 

NULL,

NULL);

 

 

го,-

~sintt4

 

 

if (ret == SOCKET.ERROR)

 

 

 

 

\\

 

 

{

 

 

 

 

,d

ЩП \\

 

 

 

 

 

printf("WSASend() failed: Xd\n",

 

 

 

 

 

 

 

 

WSAGetLastErrorO);

 

 

 

 

 

 

 

 

return;

 

 

 

 

 

 

,^,

printf("Sent: Xd bytes\n", dwBytesSent);

}

}

if (ne.lNetworkEvents & FD.CLOSE)

см.след.стр.

392 ЧАСТЬ II Интерфейс приклаМЫ"о пропмммюоаания Winsock

Листинг 12-1.

 

{продолжение)

 

 

 

 

 

 

{

 

 

 

 

 

 

 

и

 

if (ne.iErrorCode[FD_CLOSE_BIT]>

(«ОЙЯг

 

)

П

 

printf("FD_CLOSE error:

Xd\n\

 

 

 

)

 

 

ne.iErrorCode[FD_CLOSE_BlTJf; ()k<

 

 

 

else

 

 

 

 

t ) i o n a j

 

 

 

 

printf("FD_CLOSE . . . \ n " ) ;

 

r

 

 

closesocket(s);

 

 

 

 

 

{

WSACloseEvent(hEvent);

^fVtwb . 'n/893\'d

Ы :+i«e

f«Jnq

return;

 

 

 

 

 

 

{

if (ne.lNetworkEvents & FD_QOS)

 

 

 

 

}

char

buf[QOS_BUFFER_SZ];

 

 

 

 

QOS

•lpqos = NULL;

 

 

 

 

 

DWORD

dwBytes;

 

 

 

 

 

 

BOOL

bRecvRESV =

FALSE;

 

 

 

 

if

(ne.iErrorCode[FD_QOS_BIT])

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

printf("FD_QOS error:

Xd\n",

 

 

 

 

 

 

ne.iErrorCode[FD_QOS_BIT]);

 

 

i

 

if (ne.iErrorCode[FD_QOS_BIT]

== WSA_Q0S_RECEIVER5)

 

 

 

bRecvRESV = TRUE;

 

 

 

 

 

>

 

 

 

 

 

 

 

 

 

else

 

 

 

 

 

 

 

 

 

printf("FD_QOS\n");

 

 

 

(

 

dW.

lpqos

= (QOS

*)buf;

 

 

 

 

 

>ili4

ret = WSAIoctKs, SI0_GET_Q0S, NULL, 0,

 

 

 

 

 

buf, QOS_BUFFER_SZ, idwBytes, NULL, NULL);

 

 

if (ret == SOCKET_ERROR)

 

 

 

 

 

{

 

 

 

 

 

 

 

{

 

 

printf("WSAIoctl(SIO_GET_QOS)

failed: Xd\n",

 

 

 

 

WSAGetLastErrorO);

 

 

 

 

Het

 

return;

 

 

 

 

 

 

}

}

 

 

 

'

•'

 

 

 

 

PrintQos(lpqos);

 

 

 

 

 

 

//

 

 

 

 

 

 

 

//

Проверить,

возвращен

ли обьект состояния в структуре QOS,

// которая может также содержать флаг WSA_QOS_RECEIVERS

 

//

 

 

 

 

 

 

 

 

 

if (ChkForQosStatusdpqos, WSA_QOS_RECEIVERS))

 

 

 

bRecvRESV

= TRUE;

 

 

 

 

 

 

if (iSetQos == SET_Q0S_EVENT)

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

lpqos->SendingFlowspec.ServiceType =

 

 

 

 

 

clientQos.SendingFlowspec.ServiceType;

 

 

 

ret = WSAIoctKs, SI0_SET_Q0S,

lpqos,

dwBytes,

 

 

Г Л А В А 12 Качество обслуживания

393

Листинг 12-1. {продолжение)

NULL, 0, idwBytes, NULL, NULL); if (ret == SOCKET_ERROR)

pnntf("WSAIoctl(SIO_SET_QOS) failed: Xd\n"

WSAGetLastErrorO);

return;

//Изменить lSetQos, чтобы не пришлось снова включать QoS

//при приеме еще одного события FD_QOS.

//

iSetQos = SET_QOS_BEFORE;

if (bWaitToSend

&& bRecvRESV)

{

 

wbuf.buf =

databuf;

wbuf.len = DATA_BUFFER_SZ;

for(i = 0 ;

i < 1;

ret = WSASend(s, &wbuf, 1, &dwBytesSent, 0,

NULL, NULL);

if (ret == SOCKET_ERROR)

{

printf("WSASend() failed: Xd\n", WSAGetLastErrorO);

return;

A

}

printfC'Sent: Xd bytes\n",

dwBytesSent);

>

return;

//Функция: main

//Описание:

//Инициализирует Winsock, анализирует аргументы командой строки, создает

//сокет QOS TCP и вызывает соответствующую подпрограмму обработки

//в зависимости от переданных аргументов

//

int main(int argc, char **argv)

{

WSADATA

wsd;

см.след.стр.

 

 

394 ЧАСТЬ II Интерфейс прикладного программирования Winsock

Листинг 12-1.

(продолжение)

 

 

 

Л-

 

WSAPR0T0C0L_INF0 *pinfo = NULL;

 

 

 

• ,jf

 

 

SOCKET

 

 

s;

 

 

 

 

?H00# »

ti

 

 

 

 

 

 

 

 

 

}

 

// Анализ командной

строки

 

 

. Ц5У

 

 

ValidateArgs(argc,

argv);

 

 

,Jj f r t

 

 

if

(WSAStartup(MAKEW0RD(2,2), &wsd)

!= 0)

 

 

 

<

 

 

 

 

 

 

 

 

I

 

 

printf("Unable

to

load Winsock:

Xd\n", GetLastErrorO);

\\

 

 

return

- 1 ;

 

 

 

 

 

 

\\

 

>

 

 

 

 

 

 

 

 

w

 

pinfo = FindProtocolInfo(AF_INET,

SOCK_STREAH, IPPR0T0_TCP,

\\

 

 

XP1_Q0S_SUPP0RTED);

 

 

 

 

 

.,8x

if (!pinfo)

 

 

 

 

 

 

 

{

 

printf("unable to find suitable provider!\n");

 

 

 

return

-1;

 

 

 

 

 

 

'• <j

 

}

 

 

 

 

 

 

 

 

 

i.ttfdw

printf("Provider returned: Xs\n", pinfo->szProtocol);

 

 

s = WSASocket(FR0M_PR0T0C0L_INF0,

FROM_PROT0COL_INFO,

 

 

 

FROM_PROTOC0L_INFO, pinfo, 0, WSA_FLAG_OVERLAPPED); Щ-

 

 

if (s == INVALID_SOCKET)

 

 

 

 

 

 

<

 

 

 

 

 

 

 

t i

 

 

 

printf("WSASocket()

failed:

Xd\n",

WSAGetLastError())j

 

 

 

return

- 1;

 

 

 

v

,,

j , 4

 

 

>

 

 

 

 

 

лот

Aft

 

 

InitQosO;

 

 

 

 

 

 

 

 

 

if

(bServer)

 

 

 

 

 

 

 

 

 

Server(s);

 

 

 

 

 

 

 

 

else

 

 

 

 

 

 

 

 

 

 

Client(s);

 

tctUMQJttr Ш )

f e l l e d ;

M\«"

 

 

closesocket(s);

WSACleanupO; return 0;

ОдноадресныйUDP

^v*

Одноадресный UDP предоставляет больше возможностей по сравнению с TCP. Пример UDP на прилагаемом компакт-диске называется Qosudp.c. Он объединяет отправитель и приемник. Отправитель может двумя способами сообщить поставщику службы QoS о том, куда следует отправлять данные. Помните: для инициирования сеанса RSVP требуется адрес партнера. Его можно определить с помощью вызова WSAConnect или SIO_SET_QOS с объектом

QOSJDESTADDR.

Г Л А ВА 12 Качество обслуживания

395

Пример одноадресного UDP также использует параметр, сообщающий, когда необходимо включить QoS. Если пользователь хочет задать QoS до привязки или подключения, используется ioctl-команда SIO_SET_QOS с объектом QOSDESTADDR, Если принято решение включить QoS во время выполнения условной функции WSAAccept, параметры QoS указываются в вызове WSAConnect. Если пользователь желает включить QoS после установления сеанса, WSAConnect вызывается без QoS, a SIO_SET_QOS — позднее без объекта QOSJDESTADDR. Наконец, чтобы задать QoS только после получения уведомления о событии FD_QOS, SIO_SET_QOS вызывается с объектом QOSJDESTADDR, но над флагом SERVICE_QOS_NOJSIGNALING и значением поля ServiceType структуры FLOWSPEC нужно выполнить логическую операцию ИЛИ.

У принимающей стороны немного параметров. Различные флаги, указывающие, когда задавать QoS, здесь не применяются. QoS задают до приема данных или приемник ожидает, когда произойдет событие FD_QOS. Такое поведение вызвано тем, что UDP не получает никакого запроса на подключение: QoS не задана во время выполнения функции приема или после установления сеанса. Приемник имеет также возможность определить другой стиль фильтра, например, фиксированный или общий явный. Если задан другой фильтр, с параметром -г:1Р должен быть передан IP-адрес. Функция

SetQosReceivers заполняет структуру RSVPJIESERVEJNFO структурой RSVP_ FILTERSPEC, определяющей IP-адрес отправителя. Задать номер порта отправителя особенно важно. Это означает, что приемник должен знать IP-адрес каждого отправителя и номер порта, к которому он привязан.

Приемник может также использовать WSAConnect, чтобы сопоставить IPадрес отправителя сокету. Но поскольку приемник UDP вправе задать разные стили фильтров и количество отправителей, WSAConnect использовать нельзя. Помните: если WSAConnect применяется для сопоставления IP-адреса конечной точки, операции передачи и приема правомерны только для этого партнера, и ему должна быть сопоставлена QoS.

Пример с одноадресным UDP похож на пример с TCP. Различны лишь способы включения QoS на сокете. Приложения UDP требуют от отправителя задания IP-адреса приемника для вызова RSVP, а приложения TCP делают это по умолчанию, в вызове соединения. Цикл событий для обоих приложений почти одинаков. Не забудьте: для приложений UDP сокет должен быть привязан локально до включения любой QoS (передачи или приема) с SIO_SET_QOS, когда WSAConnect не используется. Допускается привязка к INADDRANYn порту 0, а также использование специального IP-адреса и порта. WSAConnect выполняет неявную привязку, поэтому если QoS включается на этом этапе, делать явную привязку заранее не нужно.

МногоадресныйUDP

Последний пример — это многоадресная QoS (файл Qosmcast.c на компактдиске). Его главная функция — WSAJoinLeaf, которую приложение должно вызвать, чтобы присоединиться к группе многоадресной рассылки. После этого оно может также передавать параметры QoS. В примере с многоадресной рассылкой использованы те же параметры, что и в примере с одноад-

396

ЧАСТЬ II Интерфейс прикладного программирования Winsock

ресной рассылкой TCP Вы можете выбрать момент задания QoS на сокете Если решите сделать это во время выполнения условной функции приема, QoS будет передана в вызов WSAJoinLeaf Или задайте QoS с помощью вызова WSAIoctl с SIO_SET_QOS

Один из параметров для приемника позволяет пользователям задать фиксированный или общий явный фильтр Помните многоадресный UDP по умолчанию использует фильтр, содержащий метасимволы Другой тип фильтра применим только к приемникам, и если требуется именно это, адрес каждого отправителя задается в параметре командной строки -г SenderIP Пользователи могут задавать фильтры через параметр -f с режимом se — для общего явного, и с режимом ff — для фиксированного фильтра

Параметр -т отправитель и получатель используют, чтобы задать многоадресную группу, к которой следует присоединиться Этот параметр можно задавать несколько раз и присоединяться к любому количеству групп Параметр -s указывает, чго программа функционирует как отправитель Параметр -w сообщает отправителю о необходимости подождать уведомления WSA_QOS_RECEIVERS цо передачи данных Наконец, параметр -q определяет, когда включать QoS, причем независимо от выбранного момента, сокет локально привязывается к порту 5150

На самом деле, можно выбрать любой порт или задать 0, чтобы порт был выбран автоматически Между тем, если получатель задает фиксированный или общий явный фильтр, он должен также сообщить IP-адрес и порт отправителя Для простоты мы используем фиксированный порт В отличие от одноадресного UDP получатель не должен локально привязывать порт, чтобы задать QoS — ведь WSAJoinLeaf неявно привязывает сокет, если он еще не привязан А вот использовать вместо WSAJoinLeaf команды сокета 1P_ADD_ MEMBERSHIP и IPJDROP MEMBERSHIP нельзя — тогда параметры QoS не будут применяться к сокету

В этом примере QoS включается почти так же, как и в случае с одноадресным UDP, поэтому мы не будем подробно на этом останавливаться Главное — представлять, как инициируется сеанс RSVP и что нужно для генерирования сообщений PATH и RSVP

ATMиQoS

Как уже упоминалось, служба QoS изначально доступна в сетях ATM Windows 2000 и Windows 98 (с SP1) поддерживают программирование ATM из Winsock QoS изначально доступна в сети ATM, так что собственные сеть, приложение и компоненты политики, необходимые для QoS через IP, не требуются Это же относится и к службе управления доступом (Admission Control Service, ACL) и к протоколу RSVP Вместо этого, коммутатор ATM выделяет пропускную способность и предотвращает ее избыточное использование

Помимо этих различий функции Winsock API работают с QoS в сетях ATM немного иначе, чем с QoS поверх IP Первое главное отличие — запрос пропускной способности QoS обрабатывается, как часть запроса соединения Это отличается от QoS поверх IP — сеанс RSVP устанавливается отдельно от соединения Если запрос пропускной способности отклонен в ATM, соеди-

Г Л А ВА 12 Качество обслуживания

397

нение установлено не будет Отсюда следует, что оба базовых поставщика ATM требуют соединения В результате не возникает проблем с заданием уровней QoS для сокета, не требующего соединения, и последующим определением конечной точки соединения

Второе и главное отличие — только одна сторона задает параметры QoS для соединения Это значит, что если клиент хочет задать QoS на соединении, отправляющая и принимающая структуры FLOWSPEC будут назначены внутри структуры QoS, переданной функции WSACOnnect Эти значения затем применятся к соединению (в QoS через IP отправитель запрашивает определенные уровни QoS и получатель осуществляет необходимое резервирование) Кроме того, прослушивающий сокет может иметь QoS, заданную с помощью WSAIoctl и SIO_SET_QOS, и ее параметры будут применены к любому входящему соединению Иными словами, QoS должна быть включена во время настройки соединения, нельзя включить QoS на уже установленном соединении

Отсюда следует, что если QoS включено для соединения, нельзя повторно согласовать параметры QoS с помощью вызова WSAIoctl и S1O_SET_QOS Заданные параметры QoS останутся неизменными до окончания соединения

Помните RSVP отсутствует, и не происходит никакого оповещения Это означает, что никакие флаги состояния не генерируются, до окончания со-

единения не происходит никаких уведомлений или событий

п (

Резюме

; £

,

QoS предлагает мощные возможности приложениям, требующим гарантированного уровня сетевого обслуживания Установка соединения QoS достаточно сложна, но это не должно вас останавливать Самое важное — знать, как и когда генерируются сообщения RSVP

i

J

! I