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

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


Скачать 2.88 Mb.
НазваниеЭ. Джонс, Д. Оланд
АнкорПрограммирование в сетях Windows.pdf
Дата12.10.2017
Размер2.88 Mb.
Формат файлаpdf
Имя файлаПрограммирование в сетях Windows.pdf
ТипКнига
#9346
страница32 из 50
1   ...   28   29   30   31   32   33   34   35   ...   50
ГЛАВА 12 Качество обслуживания
357
Каждый объект, относящийся к поставщику, содержит в качестве перво- го элемента структуру QOS_OBJECT_HDR, которая определяет тип объекта. Это необходимо, поскольку объекты в основном возвращаются внутри структуры
QOS после вызова SIOjGET^QOS. С помощью QOSJDBJECTJ4DR приложение может идентифицировать каждый объект и определить его важность. Заго- ловок объекта определен таю
typedef struct
{
ULONG ObjectType;
ULONG ObjectLength;
} QOS_OBJECT_HDR, •LPQOS_OBJECT_HDR;
ObjectType определяет тип предустановленного объекта, ObjectLength со- общает о его длине, включая заголовок. Тип объекта может быть одним из;
флагов, перечисленных в табл. 12-1.
Табл. 12-1. Типы объектов '
Объект, относящийся к поставщику
Структура объекта
QOS_OBJECT_PR1ORJTY
QOS OBJECT_SD_MODE
QOS OBJECT_TRAFFIC_CIASS
QOS_OBJECT_DESTADDR
QOS_OBJECT_SHAPER_QUEUE_DROF'MODE
QOSJ)BJECT_SHAPER_QUEUEJJM1T
RSVP_OBJECT_STATUSJNFO
RSVPJDBJECT RESERVE JNFO
RSVPJDBJECT_ADSPEC
RSVPJDBJECT POLICY JNFO
QOS_OBJECT_END_OFJJST
38. ViO
.пой
QOS_PR1ORITY
QOSSDJdODE
QOS_TRAFF1C_CLASS ^ .„
QOSJDESTADDR
QOS_SHAPER_QUEUEJJM1T_DROP_MODE
QOS_SHAPER_QUEUEJJMIT
RSVP STATUSJNFO
RSVP_RESERVE_INFO
RSVPADSPEC
RSVPJPOLICYJNFO
Отсутствует. Объектов больше нет.
Приоритет QoS
Приоритет QoS определяет абсолютный приоритет потока. Уровни приоритета лежат в диапазоне от 1 до 7, от низшего к высшему. Структура QOSPRIORTTY
определена таю typedef struct _Q0S_PRI0RITY
{
QOS_OBJECT_HDR ObjectHdr;
UCHAR
UCHAR
UCHAR
UCHAR
QOS PRIORITY,
SendPriority
SendFlags;
ReceivePriority
Unused;
•LPQOS_PRIORITY;
Эти значения определяют локальный приоритет (внутренний для отправ- ляющего узла) соответствующего трафика потока относительно трафика из других потоков. По умолчанию приоритет потока — 3- Этот приоритет ис-

3 5 8 ЧАСТЬ II Интерфейс прикладного программирования Winsock пользуется в сочетании с параметром ServiceType структуры FLOWSPEC для определения приоритета, который должен быть применен к потоку, внутрен- нему для планировщика пакетов Поля SendFlags и ReceivePrtonty в настоящее время не используются, но возможно, будут применяться в будущем
Режим отбрасывания данных
Объект QOS определяет, как элемент Packet Shaper (формировщик пакетов)
модуля ТС обрабатывает данные определенного потока Это свойство обыч- но используется, когда потоки не соответствуют параметрам, заданным в структуре FLOWSPEC, то есть если приложение передает данные со скорос- тью, превышающей заданную в поле TokenRate отправляющей структуры
FLOWSPEC Объект определяет, как локальная система действует в этом слу- чае Вот описание структуры QOS_SD_MODE
typedef struct _QOS_SD_MODE
{
QOS_OBJECT_HDR ObjectHdr,
ULONG ShapeDiscardMode,
} QOS_SD_MODE, *LPQOS_SD_MODE,
Поле ShapeDiscardMode может принимать одно из следующих значений
И TCNONCONFBORROW — поток получает ресурсы, оставшиеся после обработки всех потоков с более высоким приоритетом Потоки этого типа не подчиняются ни формировщику (Shaper), ни секвенсору (Sequencer)
Если задано значение для TokenRate, пакеты будут признаны не соответ- ствующими условиям передачи, а их приоритет — снижен до приорите- та, более низкого, чем для негарантированного трафика
Ш TCNONCONFSHAPE — должно быть задано значение для TokenRate He соответствующие пакеты будут храниться в формировщике до тех пор,
пока не станут соответствовать условиям передачи
К TCNONCONFDISCARD — должно быть задано значение для TokenRate
Не соответствующие пакеты будут отброшены
Зачем применять режим TC_NONCONF JDISCARD, если при этом данные могут быть отброшены еще до начала передачи' Это может понадобится, на- пример, при передаче звуковых или видеоданных В большинстве случаев структура FLOWSPEC настраивается для передачи пакета, размер которого равен одному кадру видео- или небольшому фрагменту звуковых данных Если по какой-либо причине пакет не соответствует условиям, нужно ли ждать,
пока он будет признан годным к передаче (как в случае с TC_NONCONF_
SHAPE)'' He лучше ли отбросить этот пакет и перейти к следующему' Для кри- тичных по времени данных, таких как видеоданные, следует именно так и поступить
<
Класс трафика QoS
Структура QOS TRAFFIC_CLASS может передавать параметр класса трафика
802 1р, поставляемый узлу сетевым устройством канального уровня

Г Л А В А 12 Качество обслуживания 359
typedef struct _QOS_TRAFFIC_CLASS
{
QOS_OBJECT_HDR ObjectHdr,
ULONG TrafficClass,
} QOS_TRAFFIC_CLASS *LPQOS_TRAFFIC_CLASS
Узлы маркируют МАС-заголовки соответствующих передаваемых пакетов значением TrafficClass, заданным в структуре Хотя эта структура включена в
Qos h, приложения не могут сами задавать приоритет
Адрес места назначения QoS
Структура QOSDESTADDR используется для задания адреса места назначе- ния для отправляющего сокета, не требующего соединения, без вызова функ- ции WSAConnect Никакие RSVP-сообщения PATH и RESV не буду! отправле- ны, пока не выяснится адрес места назначения не требующего соединения сокета Этот адрес можно задать с помощью ioctl-команды SIO_SET_QOS
typedef struct _QOS_DESTADDR
{ 4QVJ
Q0S_OBJECT_HDR ObjectHdr,
const struct sockaddr *SocketAddress,
ULONG SocketAddressLength,
} QOS.DESTADDR, •LPQOS_DESTADDR,
Поле SocketAddress ссылается на структуру SOCKADDR задающую адрес конечной точки для определенного протокола SocketAddressLength — это размер структуры SOCKADDR
Режим отбрасывания данных при переполнении очереди формировщика
Структура QOS_SHAPER_QUEUEJJMIT_DROP_MODE задает замещение стан дартной схемы отбрасывания пакетов, если достигнут лимит очереди фор- мировщика для потока Формировщик трафика (Traffic Shaper) модуля ТС
можно настроить так, чтобы он отбрасывал любые избыточные данные, если находящие в настоящий момент в очереди данные не соответствуют струк- туре FLOWSPEC Структура QOSJHAPER_QUEUEJJMIT_DROP_MODE опреде- лена так
typedef struct _QOS_SHAPER_QUEUE LIMIT DROP_MODE
{
QOS_OBJECT_HDR ObjectHdr
ULONG DropMode,
> QOS_SHAPER_QUEUE_LIMIT_DROP_MODE,
•LPQOS_SHAPER_QUEUE_LIMIT_DROP_MODE,
Возможны два значения DropMode
Ш QOSSHAPERDROPFROMHEAD — отбрасывает пакеты из начала оче- реди (действие по умолчанию),
Ш QOSSHAPERDROPINCOMING — отбрасывает любые входящие паке- ты по достижении лимита очереди

3 6 0 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Лимит очереди формировщика QoS
Структура QOSJSHAPER_QUEUE_LIMIT позволяет изменить стандартный для потока лимит очереди формировщика
typedef struct _QOS_SHAPER_QUEUE_LIMIT
<
QOS_OBJECT_HDR ObjectHdr,
ULONG QueueSizeLimit,
} QOS_SHAPER_QUEUE_LIMIT, *LPQOS_SHAPER_QUEUE_LIMIT,
QueueSizeLimit — это размер очереди формирователя в байтах Большой размер очереди формировщика предотвратит потерю данных из-за* недо- статка места в буфере
Информация о состоянии RSVP
Объект RSVP_STATUS_INFO используется для возвращения информации о состоянии и характерных ошибках RSVP
'56 V
typedef struct _RSVP_STATUS_INFO {
QOS_OBJECT_HDR ObjectHdr, )
ULONG StatusCode >
ULONG ExtendedStatusi,
ULONG ExtendedStatus2,
} RSVP_STATUS_INFO, *LPRSVP_STATUS_INFO,
Поле StatusCode — это возвращенное сообщение RSVP Возможны следу- ющие коды
Ш WSAQOS RECEIVERS — поступило хотя бы одно сообщение RSVP,
WSAQOSSENDERS — поступило хотя бы одно сообщение PATH,
WSA NO QOS RECEIVERS — отсутствуют приемники,
WSANOQOSSENDERS — отсутствуют отправители,
WSAQOSREQUESTCONFIRMED резервирование подтверждено,
WSAQOSADMISSIONFAILURE запрос отклонен из-за недостатка ре- сурсов,
WSAQOSPOLICYFAILURE запрос отклонен из-за административных причин или неверных учетных сведений,
WSAQOSBADSTYLE неизвестный или конфликтующий стиль,
WSAQOSBADOBJECT — возникла проблема с какой-либо частью струк- туры RSVPFILTERSPEC или буфером поставщика,
Ш WSAQOSTRAFFICCTRLERROR — возникла проблема с какой-либо частью структуры FLOWSPEC,
Ш WSAQOSGENERICERROR общая ошибка,
Ш ERRORIOPENDING перекрытая операция отменена
Другие два поля — ExtendedStatusi и ExtendedStatus2, зарезервированы для информации о поставщике

ГЛАВА 12 Качество обслуживания 361
м
Обычно после получения сообщения RSVP приложение получает собы- тие FD_QOS и вызывает SIO_GET_QOS для приема структуры QOS, содержа- щей объект RV_STATUS_INFO Например, для QoS-совместимого UDP-прием- ника событие FD_QOS, содержащее сообщение WSA_QOS_SENDERS, генери- руется, чтобы сообщить, что кто-то запросил службу QoS для передачи дан- ных приемнику
Информация о резервировании RSVP
Объект RSVPJRESERVEJNFO хранит RSVP-информацию для тонкой настрой- ки QoS средствами Winsock 2 QoS API и буфер со сведениями о поставщике
Объект RSVP RESERVE INFO замещает стандартный стиль резервирования и используется приемником QoS
typedef struct _RSVP_RESERVE_INFO '
{
QOS_OBJECT_HDR ObjectHdr,
ULONG Style,
ULONG ConfirmRequest,
ULONG NumPolicyElements,
LPRSVP.POLICY PolicyElementList,
ULONG NumFlowDesc,
LPFLOWDESCRIPTOR FlowDescList, j
} RSVP_RESERVE_INFO, *LPRSVP_RESERVE_INFO,
Поле Style задает тип фильтра, применяемого к этому приемнику В
табл 12-2 приведены доступные типы фильтров и типы фильтров по умол- чанию, используемые разными типами приемников
Табл. 12-2. Стили фильтров по умолчанию
Стиль фильтра Пользователи по умолчанию
Фиксированный фильтр Одноадресные приемники
UDP приемники (с установлением соединения)
Фильтр, содержащий метасимволы Многоадресные приемники
UDP-приемники (без установления соединения)
Общий явный фильтр Отсутствуют
Если значение поля ConfirmRequet отлично от 0, после приема запроса
RESV принимающим приложениям будет отправлено уведомление Поле Num-
PolicyElements связано с полем PolicyElementList Оно содержит количество объектов RSVP_POLJCY, хранимых в поле PolicyElementList (объект RSVPJPOIICY
будет описан далее в этой главе)
Рассмотрим разные стили фильтров и характеристики каждого из них более подробно
Флаг RSVPDEFAULTSTYLE сообщает поставщику службы QoS о необ- ходимости использовать стиль по умолчанию В табл 12-2 приведены сти- ли по умолчанию для разных приемников Одноадресные приемники ис-

362
ЧАСТЬ II Интерфейс прикладного программирования Winsock пользуют фиксированный фильтр, в то время как многоадресные — фильтр,
содержащий метасимволы. UDP-приемники, вызывающие WSAConnect, так- же используют фиксированный фильтр
Стиль RSVPFIXEDFILTERSTYLE обычно устанавливает один поток с гарантиями QoS между приемником и единственным источником Для одно- адресного приемника и подключенных UDP-приемников NumFlowDesc име- ет значение 1, a FlowDescList — содержит адрес отправителя Между тем, мож- но задать стиль с несколькими фиксированными фильтрами, позволяющий приемнику резервировать взаимоисключающие потоки от нескольких явно заданных источников. Например, если приемник будет получать данные от трех отправителей и требует гарантированную пропускную способность
20 кбит/с для каждого, используйте стиль нескольких фиксированных филь- тров Тогда NumFlowDesc будет иметь значение 3, a FlowDescList — содержать три адреса- по одному для каждой структуры FLOWSPEC.
Можно также присваивать каждому отправителю разные уровни QoS, но они не должны быть одинаковыми Заметьте: одноадресные приемники и под- ключенные UDP-приемники не могут использовать несколько фиксирован- ных фильтров. На рис. 12-1 показана связь между структурами FLOWDESC-
RIPTORnRSVP FILTERSPEC.
ШтШм *f
NmRttm »
f f c *
NumMws m t
Туре ш
FILT£R$PEGV4
Тур» *RLTERSPECV4
Ad#« 10 0.0.2
Type»
RLT£R$P£W4'
ИО.0.0 3 5
»
Рис. 12-1. Стиль с несколькими фиксированными фильтрами
Стиль RSVPJWILDCAKDSTYLE. Многоадресные и не подключенные UDP- приемники используют фильтр, содержащий метасимволы Для использова- ния этого стиля в случае соединений TCP или для подключенных UDP-при- емников присвойте полю NumFlowDesc значение 0, а полю FlowDescList —
NULL. Это стандартный стиль фильтра для неподключенных UDP-приемни- ков и приложений многоадресного вещания, поскольку адрес отправителя неизвестен
Стиль RSVPSHAREDEXPIICITSTYLE похож на стиль с несколькими фиксированными фильтрами, за исключением того, что сетевые ресурсы распределяются между всеми отправителями, а не выделяются для каждого
В этом случае поле NumFlowDesc равно 1, а поле FlowDescList содержит спи- сок адресов отправителей (рис 12-2).

ГЛАВА 12 Качевцюгобслуживания
363
ObfectHdr
Style я RSVP SHARED EXPLICITJTiLE
ConftrmRequest
iftumPohcyEiements
policyEiementList
NumFtQwDesc = 1
•FtowDescLtst
NumFtttms = 3
FtlterList
Type « Я1ТЕН$РШ4
Addr *AMQA
Type * FiLTERSPECW
Addr»1O.Q.0.2
Tm « HLTERSPECVM
Аййг«10.ЙДЗ I
i
F
it
Рис. 12-2. Общий явный фильтр
Последние два поля — NumFlowDesc и FlowDescList, рассматривались при обсуждении стилей RSVP Использование этих полей зависит от стиля. Num-
FlowDesc задает количество объектов FLOWDESCRIPTOR в поле FlowDescList:
typedef struct .FLOWDESCRIPTOR
Ш Ц
FLOWSPEC FlowSpec;
ULONG NumFilters;
LPRSVP_FILTERSPEC FllterLlst;
} FLOWDESCRIPTOR, «LPFLOWDESCRIPTOR;
{
Этот объект используется для определения типов фильтров для каждой структуры FLOWSPEC, передаваемых FlowSpec Поле NumFilters содержит ко- личество объектов RSVP_FILTERSPEC, имеющихся в массиве FilterList. Объект
RSVPJFILTERSPEC определен так: -- " •
typedef struct _RSVP_FILTERSPEC < -« <
FilterType Type;
union {
RSVP_FILTERSPEC_V4 FilterSpecV4;
RSVP_FILTERSPEC_V6 FilterSpecV6;
RSVP_FILTERSPEC_V6_FL0W FilterSpecV6Flow;
RSVP_FILTERSPEC_V4_GPI FilterSpecV4Gpi;
RSVP_FILTERSPEC_V6_GPI FllterSpecV6Gpi;
};
} RSVP_FILTERSPEC, •LPRSVP_FILTERSPEC;
Поле Type — это простое перечисление следующих значений:
typedef enum {
FILTERSPECV4 = 1,
FILTERSPECV6,
FILTERSPECV6_FL0W,
FILTERSPECV4_GPI,
FILTERSPECV6_GPI,
FILTERSPEC_END
} FilterType;

3 6 4 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Это перечисление задает объект, имеющийся в объединении. Вот эти спе- цификации фильтров:
typedef struct _RSVP_FILTERSPEC_V4 {
IN_ADDR_IPV4 Address;
USHORT Unused;
USHORT Port;
} RSVP_FILTERSPEC_V4, *LPRSVP_FILTERSPEC_V4;
typedef struct _RSVP_FILTERSPEC_V6 {
IN_ADDR_IPV6 Address;
USHORT UnUsed;
USHORT Port;
} RSVP_FILTERSPEC_V6, *LPRSVP_FILTERSPEC_V6;
typedef struct _RSVP_FILTERSPEC_V6_FL0W {
IN_ADDR_IPV6 Address; '!
UCHAR UnUsed; 4
UCHAR FlowLabel[3]; suv
> RSVP_FILTERSPEC_V6_FL0W, *LPRSVP_FILTERSPEC_V6_FL0W;
typedef struct _RSVP_FILTERSPEC_V4_GPI {
IN_ADDR_IPV4 Address;
ULONG GeneralPortld;
} RSVP_FILTERSPEC_V4_GPI, *LPRSVP_FILTERSPEC_V4_GPI;
typedef struct _RSVP_FILTERSPEC_V6_GPI {
IN_ADDR_IPV6 Address; ,
/fJ
ULONG GeneralPortld; ,J\
} RSVP_FILTERSPEC_V6_GPI, *LPRSVP_FILTERSPEC_V6_GPI; _,
Объект RSVP_ADSPEC
Объект RSVP ADSPEC задает информацию, передаваемую в RSVP Adspec. Этот
RSVP-объект обычно указывает, какие типы служб доступны (путем управля- емой загрузки или гарантированно), столкнулось ли сообщение PATH с не-
RSVP переходом, а также минимальный MTU по пути передачи. Его структу- ра определена так:
typedef struct _RSVP_ADSPEC
QOS_OBJECT_HDR ObJectHdr;
AD_GENERAL_PARAMS GeneralParams;
ULONG NumberOfServices;
C0NTROL_SERVICE Services[1];
} RSVP_ADSPEC, •LPRSVP.ADSPEC;
Поле GeneralParams — структура типа AD_GENERAL_PARAMS, задающая некоторые общие параметры:
typedef struct _AD_GENERAL_PARAMS

ГЛАВА 12 Качество обслуживания
365
ULONG
UL0NG
ULONG
ULONG
ULONG
IntServAwareHopCount;
PathBandwidthEstimate
MinimumLatency;
PathMTU;
Flags;
} AD_GENERAL_PARAMS, *LPAD_GENERAL_PARAMS;
IntServAwareHopCount — это количество переходов, соответствующих требованиям службы Integrated Services (IntServ). PathBandwidthEstimate
минимальная пропускная способность, доступная от отправителя до прием- ника. MinimumLatency — сумма минимальных задержек (в микросекундах)
процессов передачи пакетов в маршрутизаторах. PathMTU — максимальная единица сквозной передачи, которая не подвергается фрагментации. Поле
Flags в настоящее время не используется.
Сведения о политике RSVP
Это последний из объектов, относящихся к поставщику, который мы рассмот- рим. Он не очень понятен, так как содержит произвольное количество элемен- тов политики RSVP, которые не определены. Структура RSVPPOLJCYJNFO оп- ределена так:
typedef struct _RSVP_POLICY_INFO {
QOS_OBJECT_HDR ObjectHdr;
ULONG NumPolicyElement; '
RSVP_POLICY PolicyElement[1];
} RSVP_POLICY_INFO, *LPRSVP_POLICY_INFO;
Поле NumPolicyElement содержит информацию о количестве структур
RSVP POLICY, имеющихся в массиве PolicyElemenP.
typedef struct _RSVP_POLICY { '
USHORT Len;
USHORT Type;
UCHAR Info[4];
} RSVP_POLICY, *LPRSVP_POLICY;
Структура RSVP_POLICY'— это данные, передаваемые RSVP от имени ком- понента политики и не имеющие прямого отношения к обсуждаемым темам.
Программирование QoS
Инициирование сеанса RSVP — основная часть QoS. Пропускная способ- ность не резервируется для процесса, до тех пор пока RSVP-сообщения PATH
и RESV не будут отправлены и обработаны. Приложениям важно знать, ког- да генерируются RSVP-сообщения. До генерирования сообщения PATH от- правителю должны быть известны отправляющий элемент FLOWSPEC, IP-ад- рес и порт источника, целевой IP-адрес, порт и протокол.
Элемент FLOWSPEC становится известен всякий раз, когда вызывается поддерживающая QoS функция: например, WSAConnect, WSAJoinLeaf, WSAIoctl
(с параметром SIO_SET_QOS) и т. д. Исходный IP-адрес и порт неизвестны,
Пока сокет связан локально: неявно (например, в рамках соединения) или

366 ЧАСТЬ II Интерфейс прикладного программирования Wmsock явно. Наконец, приложению требуется место назначения данных. Необходи- мая информация собирается либо после вызова соединения, либо в случа- ях, не требующих соединений UDP. Для этого следует задать объект QOS_DE-
STADDR в данных, относящихся к поставщику (передаются с помощью ioctl- команды SIO_SET_QOS).
Для генерации RSVP-сообщения RESV также необходимо знать прини- мающий элемент структуры FLOWSPEC, адрес и порт каждого отправителя,
локальный адрес и порт принимающего сокета.
Принимающий элемент FLOWSPEC получают из любой поддерживающей
QoS функции Winsock. Адрес и порт каждого отправителя зависят от стиля фильтра, который задают вручную через относящуюся к поставщику структу-
ру RSVP RESERVE INFO. Иначе эта информация может быть получена из сооб- щения PATH. Разумеется, не всегда необходимо сообщение PATH, чтобы полу- чить адрес отправителя для генерации сообщений RESV — это зависит от типа сокета. Пример —используемый при многоадресной рассылке фильтр, содер- жащий метасимволы. Отправленное сообщение RESV применяется ко всем от- правителям в сеансе. Объяснение локального адреса и порта очевидно для одноадресных и UDP-приемников, но не для многоадресных. В случае мно- гоадресных приемников локальный адрес и порт — это адрес многоадресной рассылки и соответствующий номер его порта.
В этом разделе мы прежде всего рассмотрим различные типы сокетов и их взаимодействие с поставщиком службы QoS и RSVP-сообщениями. Затем ознакомимся с тем, как поставщик QoS сообщает приложениям об опреде- ленных событиях. Знать эти концепции, способы получения гарантий QoS,
а также условия действия и изменения этих гарантий необходимо для успеш- ного написания QoS-совместимых приложений.
RSVP и типы сокетов
Мы рассмотрим следующие типы сокетов: UDP, TCP и многоадресный UDP,
а также их взаимодействие с поставщиком службы QoS для генерации сооб- щений PATH и RESV.
Одноадресный UDP
Поскольку можно использовать и подключенные, и неподключенные соке- ты UDP, чтобы включить QoS на одноадресных сокетах UDP, нужно опреде- лить не так уж много параметров. В случае отправителя UDP отправляющая структура FLOWSPEC может быть получена от одной из вызывающих QoS
функций. Локальный адрес и порт получают либо в результате явной при- вязки, либо в ходе неявной привязки средствами WSAConnect. Последняя часть — это адрес и порт принимающего приложения, которые могут быть определены либо в WSAConnect, либо посредством относящейся к поставщи- ку структуры QOSJDESTADDR, передаваемой через параметр SIO_SET_QOS.
Если для включения QoS используется SIO_SET_QOS, сокет должен быть при- вязан заранее.
Для UDP-приемника функцию WSAConnect вызывают, чтобы ограничить принимающее приложение одним отправителем. Кроме того, приложения мо-

ГЛАВА 12 Качество обслуживания 367
гут задавать структуру QOSJDESTADDR с помощью ioctl-команды SIO_SET_QOS.
Иначе функция SIO_SET_QOS может быть вызвана без предоставления адреса места назначения. В этом случае сообщение RESV будет сгенерировано с помо- щью фильтра, содержащего метасимволы. Задавать адрес места назначения посредством функции WSAConnect или структуры QOSDESTADDR следует, толь- ко если вы хотите, чтобы приложение получало данные лишь от одного отпра- вителя, использующего стиль с фиксированным фильтром.
UDP-приемник может вызвать функцию WSAConnect и ioctl-команду
SIO_SET_QOS в любом порядке. Если первой вызвана SIO_SET_QOS, то сооб- щение RESV сначала создается с фильтром, содержащим метасимволы. Пос- ле вызова соединения предыдущий сеанс RESV прерывается, и создается но- вый сеанс со стилем фиксированного фильтра. Если же SIO_SET_QOS вызы- вается после WSAConnect и фиксированного фильтра, сообщение RSVP не прерывает сеанс RSVP и не генерирует стиль фильтра, содержащего метасим- волы. Вместо этого оно просто обновляет параметры QoS, связанные с имеющимся сеансом RSVP.
Одноадресный TCP
Сеансы TCP можно подразделить на два типа. Отправителем может быть кли- ент, подключающийся к сети и отправляющий данные. В другом случае от- правителем является сервер, к которому подключается клиент. Если отпра- витель — клиент, параметры QoS вы вправе задать прямо в вызове WSAConnect,
в результате будет отправлено сообщение PATH. Ioctl-команду SIO_SET_QOS
также можно вызвать до вызова соединения, но сообщения PATH не будут сге- нерированы, пока один из вызовов соединения не будет знать целевой адрес.
Если отправитель — сервер, он вызывает функцию WSAAccept, чтобы устано- вить соединение с клиентом. Эта функция не позволяет задавать QoS на при- нятом сокете. Если QoS задан до вызова WSAAccept с помощью SIO_SET_QOS,
любой принятый сокет наследует уровни QoS, заданные на прослушиваю- щем сокете. Вообще-то, если отправитель использует условную функцию в
WSAAccept, функция должна передать значения QoS, заданные на подключа- ющемся клиенте. Но это не так. И в Windows 98, и в Windows 2000 постав- щик службы QoS передает блок данных. Исключение.- если в Windows 98 па- раметр ipSQOS не равен 0, какие-то значения QoS должны быть заданы с по- мощью ioctl-команды SIO_SET_QOS внутри условной функции. Иначе вызов
WSAAccept не будет успешен, даже если возвратится значение CFACCEPT. QoS
можно также задать на клиентском сокете, после того как он принят.
Рассмотрим принимающие приложения TCP. Первый вариант — вызов функции WSAConnect с принимающей структурой FLOWSPEC. Когда это про- исходит, поставщик службы QoS создает запрос RESV. Если параметры QoS
не передаются WSAConnect, ioctl-команду SIO_SET_QOS задают позднее (в ре- зультате чего отправляется сообщение RESV). Последнее сочетание — это сервер, являющийся приемником, что аналогично случаю передачи. QoS
можно включить на прослушивающем сокете до вызова WSAAccept, при этом клиентский сокет наследует те же самые уровни QoS. Иначе QoS включается в условной функции или после приема сокета. В любом случае поставщик служ- бы QoS генерирует сообщение RESV, как только поступает сообщение PATH.

368 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Многоадресная рассылка
Многоадресные отправители действуют так же, как отправители UDP, но функ- ция WSAJoinLeaf используется, чтобы стать членом многоадресной группы (в противоположность вызову WSAConnect с адресом места назначения). QoS
можно включить с помощью WSAJoinLeaf или отдельно, посредством вызова
SIO_SET_QOS. Адрес сеанса многоадресной рассылки используется для форми- рования объекта сеанса RSVP, включенного в RSVP-сообщение PATH.
В случае многоадресного приемника сообщения RSVP не будут генериро- ваться, пока не определен адрес многоадресной рассылки с помощью функ- ции WSAJoinLeaf. Поскольку многоадресный приемник не задает адрес парт- нера, поставщик службы QoS генерирует сообщения RESV со стилем фильт- ра, содержащего метасимволы. Поставщик службы QoS не запрещает сокету присоединяться к нескольким многоадресным группам. В этом случае по- ставщик отправляет сообщения RESV для всех групп, имеющих соответст- вующее сообщение PATH. Параметры QoS, передаваемые каждой функции
WSAJoinLeaf используются в каждом сообщении RESV. Но если функция SIO_
SET_QOS вызвана на сокете после присоединения к нескольким группам,
новые параметры QoS применяются ко всем многоадресным группам, к ко- торым присоединился сокет.
Когда данные отправляются многоадресной группе, QoS применяется только к данным, отправляющимся группе, к которой присоединился отпра- витель. Другими словами, если вы присоединяетесь к одной многоадресной группе и используете функцию sendto/WSASendTo, имеющую любую другую многоадресную группу в качестве места назначения, QoS к этим данным не применяется. Кроме того, если сокет присоединяется к многоадресной груп- пе, задающей определенное направление (например, SENDERJDNLY' или JL_
RECEIVERjDNLY в параметре dwFlags, передаваемом функции WSAJoinLeaf),
QoS применяется соответственно. Сокет, настроенный только для приема, не получит никаких преимуществ QoS для отправленных данных.
Уведомления QoS
Мы рассказали, как вызвать QoS для сокетов TCP, UDP, многоадресного UDP,
о соответствующих RSVP-событиях, происходящих в зависимости от того,
отправляете вы данные или получаете. Между тем, завершение этих сообще- ний RSVP не строго привязано к вызовам API, которые их инициируют. Вы- зов WSAConnect для принимающего ТСР-сокета генерирует сообщение RESV,
но это сообщение не зависит от вызова API: вызов возвращается, не подтвер- ждая резервирования и выделения сетевых ресурсов. По этой причине было добавлено новое асинхронное событие FD_QOS, передаваемое сокету.
Как правило, уведомление о событии ED_QOS передается, если имеется:
• уведомление о принятии или отклонении запроса QoS от приложения;
• значительные изменения в QoS, переданные сетью (не совместимые с со- гласованными значениями);
Ш состояние, определяющее, готов ли партнер QoS передавать или прини- мать данные для определенного потока.

Г Л А В А 12 Качество обслуживания 369
Регистрация для получения уведомлений FD_QOS
Чтобы получать уведомления о событиях FD_QOS, приложение должно за- регистрироваться. Для этого существует несколько способов. Прежде всего можно воспользоваться функцией WSAEventSelect или WSAAsyncSelect и вклю- чить флаг FD_QOS в побитовую операцию ИЛИ над флагами событий. Од- нако приложение готово продолжать прием события FD_QOS, только если уже был сделан вызов одной из инициирующих QoS функций. Заметьте: в некоторых случаях приложению может потребоваться получить событие
FD_QOS без задания уровней QoS на сокете. Этого можно достичь, задав структуру goS, отправляющие и принимающие элементы FLOWSPEC которой содержат флаг QOS_NOT_SPECIFIED или SERVICETYPE_NOTRAFFIC. При этом над флагами SERVICE_NO_QOS_SIGNALING и SERVICETYPE_NOTRAFF1C необхо- димо выполнить логическую операцию ИЛИ для направления QoS, в кото- рой вы хотите получить уведомление о событии.
Подробнее о вызовах двух асинхронных функций выбора — в главе 8.
Если вы используете WSAEventSelect после того, как событие произошло, вы- зовите функцию WSAEnumNetworkEvents, чтобы получить дополнительные доступные коды состояния. Эта функция также описана в главе 8, но мы рас- смотрим ее и в этой главе, так как она важна для приложений QoS. Передайте описатель сокета, описатель события и объект WSANETWORKEVENTS вызову функции, который вернет информацию о событии этой структуре.- typedef struct .WSANETWORKEVENTS
{
long INetworkEvents;
int iErrorCode[FO_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
Поле INetivorkEvents будет хранить результат логической операции ИЛИ
для всех сработавших флагов события. Чтобы обнаружить, что событие про- изошло, просто выполните логическую операцию И (оператором &) над этим полем и флагом события. Если результат отличен от 0, событие про- изошло. Массив iErrorCode сообщит об ошибках или, в случае QoS, проин- формирует о состоянии.
Если событие произошло, относящийся к нему флаг используется для указания позиции в этом массиве. Если индекс массива равен 0, ошибки не было, иначе индекс укажет на элемент массива, содержащий код ошибки. На- пример, если событие FD_QOS произошло, используйте флаг FD_QOS_BITдля указания на массив iErrorCode, чтобы проверить любые ошибки или получить информацию о состоянии. Все другие асинхронные события (FD_READJ3IT,
FD_WR1TEJ3ITи т. п.) имеют похожие флаги указателей.
Уведомления RSVP
Существуют два способа приема уведомлений QoS. Оба они тесно связаны с темой этого раздела, то есть получением результатов события QoS. Если вы за- регистрировались для получения уведомлений FD_QOS посредством WSA-
ASyncSelect или WSAEventSelect и действительно получаете уведомление о собы-

3 7 0 ЧАСТЬ II Интерфейс прикладного программирования Wmsock тии FD_QOS, вызовите WSAIoctl с ioctl-параметром SIO_GET_QOS, чтобы выяс- нить, чем вызвано событие На самом деле, регистрироваться для получения событий FD_QOS не обязательно — можно просто вызвать WSAIoctl с коман- дой SIO_GET_QOS, воспользовавшись перекрытым вводом-выводом Для это- го определите порядок завершения, вызываемый, когда поставщик службы
QoS обнаруживает изменение в QoS Когда произойдет обратный вызов, струк- тура QoS будет доступна в выходном буфере
В любом случае, если в QoS произошло изменение, ваше приложение бу- дет уведомлено о нем посредством регистрации для FD_QOS или путем ис- пользования перекрытого ввода-вывода и SIO_GET_QOS Если вы регистри- руетесь для FD_QOS, то при уведомлении о событии нужно также вызывать
WSAIoctl с ioctl-командой SIO_GET_QOS В обоих случаях возвращаемая струк- тура QOS содержит информацию только по одному направлению Другими словами, полю ServiceType структуры FLOWSPEC для неверного направления должно быть присвоено значение SERVICETYPE_NOCHANGE Если произош- ло несколько событий QoS, вызывайте WSAIoctl и SIO_GET_QOS в цикле, пока не будет возвращено значение SOCKET_ERROR, и WSAGetLastError не вернет значение WSAEWOULDBLOCK
Последняя тонкость при вызове SIO_GET_QOS — размер буфера Когда вы- зывается событие FD_QOS, возможно, будут возвращены объекты, относящи- еся к поставщику Но чаще, если буфер достаточно велик, все же возвратится структура RSVP_STATUS_INFO О выборе размера буфера мы рассказали ра- нее, при рассмотрении WSAIoctl
Если приложение использует одну из функций асинхронных событий,
помните когда произошло событие FD_QOS, всегда следует выполнить опе- рацию SIO_GET_QOS, чтобы заново активизировать уведомления FD_QOS
Теперь обсудим существующие типы уведомлений Первая и наиболее оче- видная причина для события QoS — это изменение параметров FLOWSPEC для определенного потока Например, если вы настраиваете сокет с негаранти- рованным обслуживанием, поставщик службы QoS будет периодически от- правлять уведомление приложению, информируя его о текущем состоянии сети Кроме того, если вы задаете контролируемую нагрузку и т п, после резервирования QoS-параметры размера корзины и скорости поступления блоков данных могут немного отличаться от тех, которые вы запросили
После приема уведомления QoS приложение должно сравнить возвращен- ное значение FLOWSPEC с запрошенным и убедиться, что может продолжать рабогу
В течение всего времени существования QoS-совместимого сокета вы можете выполнить SIO_SET_QOS, чтобы изменить любые параметры, в ре- зультате чего будет сгенерировано уведомление партнеру или партнерам,
связанным с текущим сеансом RSVP Надежное приложение должно уметь обрабатывать эти ситуации
Кроме обновления параметров QoS уведомление о событии QoS опове- щает также о других событиях, таких как уведомления об отправителях или приемниках Коды возможных событий приведены в разделе < Информация о состоянии RSVP» Получить эти коды можно, во-первых, как часть объекта

Г Л А В А 12 Качество обслуживания
371
RSVP_STATUSJNFO Когда происходит событие QoS и вызывается SIO_GET_QOS,
объект RSVP STATUSJNFO будет возвращен как часть буфера, относящегося к поставщику
Второй способ — если вы используете WSAEventSelect, чтобы зарегистри- роваться для получения событий, эти коды вернутся в структуре WSANET-
WORKEVENTS, возвращаемой из WSAEnumNetworkEients Коды также можно найти в массиве lErrorCode, проиндексированном по полю FD_QOSJ3IT Пер- вые пять из перечисленных кодов не являются кодами ошибок Они возвра- щают важную информацию о состоянии соединения QoS Остальные коды состояния не мешают передавать или принимать данные — они просто ука- зывают на ошибку в сеансе QoS Очевидно, что отправленные в такой ситу- ации данные не будут соответствовать запрошенным гарантиям QoS
Уведомления WSAQOS RECEIVERS и WSAQOS NO RECEIVERS. При одноадресной рассылке после того, как отправитель начинает работу и по- лучает первое сообщение RSVP, приложению передается WSA_QOS RECEI-
VERS Если приемник выполняет какие-либо действия по отключению QoS,
генерируется сообщение RESV После того, как отправитель получит это со- общение, приложению передается WSA_QOS_NO_RECEIVERS Очевидно, что при одноадресной рассылке многие приемники закрывают сокет, генерируя события FD_CLOSE и WSA_QOS_NO RECEIVERS В большинстве случаев в от- вет приложение закрывает отправляющий сокет
При многоадресной рассылке передающее приложение получает WSA_
QOSJRECEVERS всякий раз, когда число приемников изменяется и отлично от 0 Другими словами, при многоадресной рассылке отправитель получает
WSA_QOS_RECEIVERS всякий раз, когда приемник QoS присоединяется к груп- пе или выходит из группы, до тех пор пока остается хотя бы один приемник
Уведомления WSA QOSSENDERS и WSA QOS NOSENDERS. Уведомле- ние отправителя аналогично событию приемника, за исключением того, что связано с приемом сообщения PATH При одноадресной рассылке после нача- ла работы прием первого сообщения PATH генерирует WSA_QOS_SENDERS, в то время как сообщение PATH инициирует сообщение WSA_QOS_NO_SENDERS
Аналогичным образом при многоадресной рассылке приемники получа- ют уведомление WSA_QOS_SENDERS всякий раз, когда число отправителей изменяется и отлично от 0 Когда число отправителей доходит до 0, прило- жению передается сообщение WSA_QOS_NO_SENDERS
Уведомление WSAQOSREQUESTCONFIRMED последнее сообще- ние о состоянии С его помощью приложения QoS уведомляются о подтвер- ждении запроса на резервирование В структуре RSVP_STATUS_INFO имеет- ся поле ConfirmRequest Если его значение отлично от 0, поставщик службы
QoS уведомляет приложение о подтверждении запроса на резервирование
Этот объект — параметр, относящийся к поставщику, он может передавать- ся вместе со структурой QoS команде SIO_SET_QOS
Шаблоны QoS
В Winsock есть несколько предопределенных структур QoS, называемых шаблонами, которые приложение может вызвать по имени Эти шаблоны

372 ЧАСТЬ II Интерфейс прикладного программирования Winsock определяют параметры QoS для нескольких широко используемых звуковых и видеокодов, таких как G711 и H263QCIF. Функция WSAGetQOSByName оп- ределена так:
BOOL WSAGetQOSByName(
SOCKET s,
LPWSABUF lpQOSName,
LPQOS lpQOS
);
Если вы не знаете имен имеющихся шаблонов, можете воспользоваться этой функцией для их перебора. Для этого выделите достаточно большой буфер в lpQOSName, присвойте его первому символу значение 0 и передай- те нулевой указатель в lpQOS:
WSABUF
char
cbuf[O]
wbuf.buf
wbuf.len
wbuf;
cbuf[1024];
= Л0 1
;
= cbuf;
= 1024;
WSAGetQOSByName(s, &wbuf, NULL);
По возвращении буфер символов содержит массив строк, разделенных нулевыми символами. Список завершается еще одним нулевым символом.
Это означает, что последняя строка будет иметь два последовательных ну- левых символа. Из этого массива можно получить имена всех имеющихся шаблонов и запросить один из них. Следующий код реализует поиск шаб- лона G711:
QOS qos;
WSABUF wbuf;
wbuf.buf = "6711";
wbuf.len = 4;
WSAGetQOSByName(s, &wbuf, &qos);
Если запрашиваемого шаблона не существует, поиск возвращает FALSE и генерируется ошибка WSAEINVAL. В случае успеха функция возвращает TRUE.
Пример Qostemplate.c на прилагаемом компакт-диске показывает, как пере- бирать имеющиеся шаблоны QoS.
Кроме того, вы можете создать свой собственный шаблон QoS, чтобы другие приложения могли запрашивать его по имени. Здесь задействованы две функции — WSCInstallQOSTemplate и WSCRemoteQOSTemplate. Первая —
создает шаблон QoS, вторая — его удаляет. Вот прототипы этих функций:
BOOL WSCInstallQOSTemplate(
const LPGUID lpProviderld,
LPWSABUF lpQOSName,
LPQOS lpQOS

12 КачестводрслужИммбМ 373
BOOL WSCRemoveQOSTemplate( ^(;* , ^ а ц м ^ >1Ци *y»$ftft,-- W
const LPGUID lpProviderld,^ ,
лш
^
ш
,,
< M S t татада -* i
LPWSABUF lpQOSName * ' ""**
Описание этих функций очевидно. Для создания шаблона вызовите WSC-
InstallQOSTemplate с GUID именем шаблона и параметрами QoS. GUID — это уникальный идентификатор для этого шаблона, который может быть сгене- рирован с помощью таких утилит, как Uuidgen.exe.
Для удаления шаблона просто передайте его имя вместе с тем же GUID,
что использовался при его задании, функции WSCRemoveQOSTemplate. В слу- чае успеха обе функции возвращают TRUE.
Примеры
Рассмотрим примеры программ, использующих QoS. Первый пример с TCP —
наиболее простой, потому что требует соединения. Второй — использует
UDP без каких-либо вызовов соединений. В последнем примере показано применение многоадресного UDP. Во всех трех примерах мы воспользуем- ся функцией WSAEventSelect, поскольку она проще WSAAsyncSelect. Здесь при- веден полный пример программы для одноадресной рассылки TCP и толь- ко важнейшие фрагменты программ для UDP и многоадресной рассылки.
Дело в том, что многие концепции одинаковы, независимо от типа исполь- зуемого сокета. Полные примеры программ находятся на прилагаемом ком- пакт-диске. Все три примера основаны на вспомогательных процедурах
PrintQos и FindProtocolInfo, описанных в файлах Printqos.c и Provider.c. Пер- вая — просто печатает содержимое структуры QoS, вторая — находит про- токол из каталога поставщика с требуемыми атрибутами, такими как QoS.
Одноадресный TCP
Пример одноадресного TCP приведен в листинге 12-1. Код для этого приме- ра находится в папке Chapter 12 в файле Qostcp.c. Этот пример объемный,
но не очень сложный. Основная часть кода — обычный код WSAEventSelect.
Единственное исключение — это действия в случае события FD_QOS. Глав- ная функция не делает ничего необычного. Аргументы анализируются, со- здается сокет и вызывается функция Server или Client, в зависимости от того,
как используется приложение: в качестве сервера или клиента. Сначала рас- смотрим клиентское соединение.
Во всех трех примерах параметр командной строки сообщает, когда вклю- чать QoS: до, во время, после соединения или после того, как партнер зап- росит локальное включение QoS. Перечислим эти параметры:
-q:[b,d,a,e] — задает QoS до (Ь), во время (d) или после (а) или ожидает события FD_QOS (e) до задания;
• -s — работает как сервер;
• -c:Server-IP — работает как клиент и подключается к серверу по задан- ному адресу;

374 ЧАСТЬ II Интерфейс прикладного программирования Winsock
И -w — для передачи данных ожидает приема сообщения RESV;
Ш -г — задает параметр для получения уведомления после подтверждения резервирования.
Если QoS включается до соединения (для клиента), привяжите сокет к произвольному порту и затем вызовите SIOSET_QOS с отправляющей струк- турой FLOWSPEC. Заметьте: осуществлять привязку до вызова SIO_SET_QOS не обязательно, поскольку адрес партнера неизвестен до вызова соединения и
RSVP-сеанс пока не может быть инициирован.
Если пользователь включает QoS во время соединения, структура QOS пе- редается вызову WSAConnect. Этот вызов инициирует сеанс RSVP и подклю- чает клиента к заданному серверу. (Можно избрать и другой способ: чтобы программа ожидала, пока партнер не включит QoS и структура QoS не бу- дет передана WSAConnect!) Код берет отправляющую структуру QoS, переда- ет результат логической операции ИЛИ над флагом SERVICE_NO_QOSSIG-
NALING полю ServiceType в структурах FLOWSPEC и вызывает WSAIoctl с ioctl- командой SIO_SET_FLAG. Тем самым дается указание поставщику службы QoS
не вызывать ТС, но продолжать поиск сообщений RSVP.
После включения QoS регистрируются события, которые хочет получать клиент, включая FD_QOS. Заметьте: QoS нужно включить на сокете заранее,
чтобы приложение запросило принимающее FD_QOS. После этого клиент ожидает в цикле по WSAWaitForMulttpleEvents, который завершается, когда одно из выбранных событий свободно. Когда происходит событие, события перечисляются вместе с любыми ошибками в WSAEnumNetworkEvents.
В основном Qostcp.c обрабатывает другие события, типа FD_READ,FD_WRLTE
nFD_CLOSE (СМ. пример программы с WSAEventSelect в главе 8). Но обратите внимание на событие FD_WRITE. Один из параметров командной строки ожидает приема RSVP-сообщения PATH до передачи данных. Это особенно важ- но, если передаваемые данные могут превысить негарантированную пропуск- ную способность сети. Функция AbleToSend вызывает SIO_CHK_QOS, чтобы оп- ределить, находятся ли запрашиваемые параметры QoS в доступных негаран- тированных пределах. Если это так, можно отправлять данные, если нет —
следует ожидать подтверждения.
В рассматриваемом случае клиента мы хотим получить сообщение
WSA_QOS_RECEIVERS, указывающее на прием сообщения RESV при получе- нии события FD_QOS. На этом этапе мы вызываем команду SIO_CHK_QOS,
чтобы получить информацию о состоянии. Флаг WSA_QOS_RECEIVERS может быть возвращен двумя способами. Во-первых, в поле iErrorCode структуры
WSANETWORKEVENTS как элемент, проиндексированный по полю FDJ)OS_BLT.
Второй вариант — структура RSVP_STATUSJNFO возвращается в буфере, пе- реданном функции WSAIoctl с помощью ioctl-команды SIO_GET_QOS. Эта структура также может содержать флаг W$A_QOS_ RECEIVERS в поле Status-
Code. Если было задано ожидание передачи флага, мы проверяем поле ошиб- ки WSANETWORKEVENTS, чтобы определить, была ли возвращена структура
RSVPJSTATUS INFO. Если флаг присутствует, отправляем данные.
Часть программы, касающаяся сервера, сложнее, но только потому, что обрабатывает несколько клиентских соединений или их отсутствие. Прослу-

Г Л А В А 12 Качество обслуживания 375
шивающий сокет и клиентские сокеты обрабатываются в одном массиве с именем sc. Нулевой элемент массива — это прослушивающий сокет, осталь- ные — возможные клиентские соединения. Глобальная переменная nConns
содержит число имеющихся клиентов. По окончании клиентского соедине- ния все активные сокеты сдвигаются к началу массива. Существует также соответствующий массив описателей событий.
Сначала сервер привязывает прослушивающий сокет, и если пользователь решает включить QoS до приема клиентских соединений, включает прием
QoS. Любые параметры QoS, заданные на прослушивающем сокете, копиру- ются в клиентское соединение (если сервер не использует AcceptEx). Прослу- шивающий сокет регистрируется для приема только событий FDACCEPT.
Оставшаяся часть процедуры сервера — это цикл, ожидающий события в массиве описателей сокетов. Сначала единственный сокет в массиве —
прослушивающий, но по мере установки клиентских соединений будет по- являться больше сокетов и соответствующих им событий. Если цикл WSA-
WaitForMultipleEvents завершается по причине происшедшего события и опи- сатель события в массиве указывает на нулевой элемент, то событие проис- ходит на прослушивающем сокете. В этом случае программа вызывает WSA-
EnumNetworkEvents, чтобы выяснить, какое событие происходит. Если собы- тие происходит на клиентском сокете, программа вызывает процедуру об- работки HandleClientEvents.
Обратите внимание на событие FD_ACCEPTна прослушивающем сокете.
Когда оно происходит, вызывается WSAAccept с условной функцией. Помни- те: параметры QoS, передаваемые в условную функцию, не надежны, и если в Windows 98 такой параметр отличен от 0, нужно задать какую-нибудь QoS.
Windows 2000 не имеет этого ограничения, и QoS можно включить в любой момент. Если пользователь решает включить QoS во время принимающего вызова, это происходит в условной функции. Когда клиентский сокет при- нят, создается соответствующий описатель события, и события регистриру- ются для сокета.
Функция HandleClientEvents обрабатывает любые события, происходящие на клиентских сокетах. События чтения и записи очевидны; единственный вопрос — нужно ли ожидать подтверждения резервирования до передачи данных. Если пользователь решит, что да, клиент ожидает возвращения со- общения WSA_QOS_RECEF/ERS в событии FD_QOS. Если сообщение возвраща- ется, передача данных не начинается до приема FD_QOS. Наиболее важная часть этого примера — включение QoS на сокете и обработка FD_QOS.
Листинг 12-1. Пример одноадресного TCP (Qostcp.c)
// Модуль: Qostcp.c
//
«include
«include
«include
«include
см. след. стр.

376 ЧАСТЬ II Интерфейс прикладного прогЙШЛрования Winsock
Листинг 12-1. (продолжение)
«include "provider.h"
«include "printqos.h"
«include
«include
«define QOS_BUFFER_SZ
«define DATA_BUFFER_SZ
«define SET_Q0S_N0NE
«define SET_QOS_BEFORE
«define SET_QOS_DURING
«define SET_QOS_AFTER
«define SET_QOS_EVENT
«define HAX_C0NN
int iSetQos,
nConns;
BOOL bServer,
bWaitToSend,
bConfirmResv;
char szServerAddr[64];
QOS clientQos,
serve rQos;
16000 // Размер буфера по умолчанию для
// SIO_GET_Q0S
2048 // Размер буфера для передачи/приема данных
0 1
2 3
4 10
// QOS отсутствует
// Включить QOS на прослушивающем сокете
// Включить QOS в условном приеме
// Включить QOS после приема
// Дождаться FD_QOS и затем включить
// Когда включить QOS?
// Клиент или сервер?
// Ожидать передачи данных,
// Адрес сервера
// Структура клиента QOS
// Структура сервера QOS
пока не выполнится RESV
RSVP_RESERVE_INFO qosreserve;
// Создать несколько общих структур FLOWSPEC
//
const FLOWSPEC flowspec_notraffle = {QOS_NOT_SPECIFIED,
QOS_NOT_SPECIFIED,
QOS_NOT_SPECIFIED,
QOS_NOT_SPECIFIED,
QOS_NOT_SPECIFIED,
SERVICETYPE.NOTRAFFIC,
QOS_NOT_SPECIFIED,
QOS_NOT_SPECIFIED};
const FLOWSPEC flowspec_g711 = {8500,
680,
17000,
QOS_NOT_SPECIFIED,
QOS_NOT_SPECIFIED,
SERVICETYPE.CONTROLLEDLOAD,
340,
340};

1   ...   28   29   30   31   32   33   34   35   ...   50


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