Сокеты
Использование сокета несколькими процессами одновременно организовано следующим образом. Базовый процесс для получения специальной структуры WSAPROTOCOL_INFO вызывает WSPDuplicateSocket. Эта процедура для передачи структуры другому процессу применяет межпроцессный механизм коммуникаций (IPC). Последний процесс использует структуру WSAPROTOCOL_INFO при обращении к WSPSocket. Дескриптор сокета, полученный в результате этой операции, будет дополнительным дескриптором исходного сокета, который с этого момента может использоваться двумя процессами.
Такой механизм разработан для того, чтобы удовлетворить как требованиям однопроцессной версии, так и многопроцессным вариантам Windows NT и XP. Следует иметь в виду, что совместное использование сокетов несколькими процессами возможно и без использования WSPDuplicateSocket, так как дескриптор сокета доступен для всех процессов.
Когда формируется дескриптор нового сокета IFS-провайдер должен вызвать WPUModifyIFSHandle, а неIFS-провайдер должен вызвать WPUCreateSocketHandle (IFS Installable File System).
Так как реально дублируются дескрипторы, а не сами сокеты, все параметры соединения оказываются абсолютно идентичными.
Контроль состояния используемых совместно сокетов осуществляется посредством WSPAsyncSelect и WSPEventSelect. Вызов одного из указанных запросов с одним из дескрипторов сокета в качестве параметра аннулирует любую предшествующую регистрацию событий для указанного сокета, вне зависимости от того, какой из дескрипторов применен для новой регистрации. Таким образом, нельзя для процесса A иметь FD_READ -события, а для процесса B получать FD_WRITE -события.
Процесс может вызвать WSPCloseSocket для дублирующего сокета и старый дескриптор будет ликвидирован, в то время как сам сокет, ему соответствующий, останется открытым вплоть до выполнения процедуры WSPCloseSocket.
Два или более дескрипторов могут соответствовать одному и тому же сокету и использоваться независимо для операций ввода/вывода. Однако интерфейс WinSock не осуществляет какого-либо контроля за доступом, задача координации совместного использования сокета является объектом ответственности самих процессов.
Для простоты в дальнейшем термин "многоточечный" будет означать широковещательный или мульти-кастинговый.
В настоящее время многоточечные приложения (напр., IP-мультикастинг, STII, T.120, ATM UNI, и т.д.) значительно различаются по способу подключения узла к многоточечной сессии. Для декларации различных многоточечных атрибутов протокола в WinSock 2 используется структура WSAPROTOCOL_INFO. Просматривая эти атрибуты, программист может узнать, какие соглашения должны быть реализованы.
В плоскости управления существует два типа различных сессий: rooted и nonrooted (корневые и некорневые). В случае корневого управления существует участник, называемый c_root, отличающийся от всех остальных членов многоточечной сессии, которые называются c_leaf (периферийные члены группы). Участник сессии c_root должен оставаться в списке участников на протяжении всей многоточечной сессии, так как без его участия сессия будет прервана. c_root обычно инициирует многоточечную сессию путем установления связей с участниками типа c_leaf. c_root может вводить членов в группу, но c_leaf может подключиться к c_root позднее.
Для некорневой плоскости управления все участники многоточечной сессии являются периферийными узлами, и не существует какогото выделенного узла. Каждый c_leaf должен подключиться к многоточечной сессии, которая либо существует всегда (как в случае IP-мультикастинг адреса), либо создана за счет какого-то внешнего механизма. При другом подходе c_root по-прежнему существует, но принадлежит сети в целом (не является одним из участников сессии). Так как корневой узел существует, некорневая управляющая плоскость может рассматриваться как неявно корневая. Примерами такого рода неявно корневых схем являются система IP-мультикастинга — многоточечные блоки управления (Multipoint Control Unit — MCU) в H.320-видеоконференциях и т.д.
В плоскости данных также существует два стиля передачи информации: rooted и nonrooted (корневой и некорневой). В корневой плоскости данных имеется выделенный участник, называемый d_root. Обмен данными происходит исключительно между d_root и остальными участниками многоточечной сессии, которые называются d_leaf. Трафик может быть однонаправленным или двунаправленным. Данные, посланные d_root, будут доставлены всем d_leaf, в то время как данные, отправленные d_leafs, попадут только в d_root. В случае корневой плоскости данных не существует потока данных между периферийными узлами группы ( d_leaf ).
В некорневой плоскости данных все участники эквивалентны и любая информация, посланная участником, будет доставлена всем членам группы (сессии). Аналогично, каждый узел d_leaf может получать данные ото всех остальных узлов группы, а также от любых узлов, не участвующих в данной сессии.
В структуре WSAPROTOCOL_INFO имеется три поля атрибутов для выделения различных схем, используемых в плоскостях управления и данных.
- XP1_SUPPORT_MULTIPOINT = 1 указывает на то, что этот протокол поддерживает многоточечные коммуникации, а последующие два поля имеют смысл.
- XP1_MULTIPOINT_CONTROL_PLANE определяет, является ли плоскость управления корневой ( = 1 ) или не корневой ( = 0 ).
- XP1_MULTIPOINT_DATA_PLANE указывает, является ли плоскость данных корневой ( = 1 ) или некорневой ( = 0 ).
В определенные моменты сокеты, включенные в многоточечную сессию, могут по своему поведению отличаться от сокетов типа точкаточка. Так, сокет вида d_leaf в корневой плоскости данных может только посылать информацию участнику d_root. Поэтому клиент должен иметь возможность заявить об этом на стадии формирования сокета. Делается это с помощью четырех многоточечных атрибутных флагов, которым присваивается определенное значение через параметр dwFlags в WSPSocket.
- SA_FLAG_MULTIPOINT_C_ROOT служит для создания сокета, работающего как c_root. Это разрешено, если в WSAPROTOCOL_INFO указано, что существует контекст корневой плоскости управления.
- WSA_FLAG_MULTIPOINT_C_LEAF предназначен для генерации сокета, работающего как c_leaf. Это возможно, если XP1_SUPPORT_MULTIPOINT присутствует в соответствующей записи WSAPROTOCOL_INFO.
- WSA_FLAG_MULTIPOINT_D_ROOT предполагает формирование сокета, работающего как d_root. Это позволено, если в WSAPROTOCOL_INFO указано, что существует контекст корневой плоскости данных.
- WSA_FLAG_MULTIPOINT_D_LEAF служит для создания сокета, работающего как d_leaf. Это допускается, если XP1_SUPPORT_MULTIPOINT присутствует в соответствующей записи WSAPROTOCOL_INFO.
Когда создается многоточечный сокет, один из двух флагов плоскости управления и один из двух флагов плоскости данных должны быть заданы в параметре dwFlags WSPSocket. Таким образом, при создании многоточечного сокета могут быть реализованы четыре возможности: c_root/d_root, c_root/d_leaf, c_leaf/d_root, или c_leaf/d_leaf.
При использовании мультикастинга обычно необходимо специфицировать способ реализации сессии. Среди параметров сессии важную роль играет число вовлеченных сетевых сегментов. Для регулирования этого числа используется команда SIO_MULTICAST_SCOPE WSPIoctl. Нулевое значение числа сетевых сегментов означает, что мультикастинг-пакеты не покинут пределы ЭВМ и могут попадать только во внутренние сокеты. Значение единица (число по умолчанию) указывает, что мультикастинг-пакеты не могут выйти за пределы маршрутизатора локальной сети. Большие величины позволят распространение сообщений, проходящих соответствующее число маршрутизаторов. Этот код идентичен параметру времени жизни (TTL) в IP-мультикастинге.
Многоточечный сокет часто характеризуется его ролью в плоскости данных и управления. Следует иметь в виду, что один и тот же сокет может иметь совершенно разную роль в разных плоскостях.
В схемах для корневой плоскости периферийные узлы добавляются в многоточечную группу одним из двух способов. В первом методе корень использует WSPJoinLeaf для инициализации соединения с периферийным узлом и приглашает его быть участником сессии. Со стороны периферийного узла приложение должно создать c_leaf -сокет и использовать WSPListen для установки его в режим ожидания (listen). Периферийный узел получит сообщение FD_ACCEPT, которое означает приглашение присоединиться к многоточечной сессии, и может объявить о своем желании подключиться путем вызова WSPAccept. Корневое приложения получит сообщение FD_CONNECT, когда операция подключения к группе завершена.
Во втором методе роли меняются. Корневой клиент создает сокет c_root и переходит в режим ожидания ( listen ). Периферийный узел, желающий присоединиться к сессии, создает сокет c_leaf и запускает WSPJoinLeaf, чтобы инициализировать подключение и доступ. Корневой клиент получает FD_ACCEPT, когда приходит запрос доступа, и принимает периферийный узел в группу посредством запроса WSPAccept. Периферийный узел получает FD_CONNECT, когда он принят в группу. Для случая IP-мультикастинга это эквивалентно опции сокета IP_ADD_MEMBERSHIP. Читателей, знакомых с использованием несвязного UDP-протокола в IP-мультикастинге, может смутить присутствующая здесь семантика, ориентированная на соединение. В частности, указание на то, что используется запрос WSPJoinLeaf для сокета UDP и ожидание сообщения FD_CONNECT могут вызвать недоразумение. Существуют уже, однако, прецеденты использования такой семантики для протоколов, не ориентированных на соединение. Разрешено и иногда полезно, например, использовать процедуру WSPConnect для UDP-сокетов. Общим результатом применения семантики, ориентированной на соединение для несвязных сокетов, является ограничение на то, как эти сокеты могут использоваться. UDP-сокет, реализуемый в WSPJoinLeaf, будет иметь определенные ограничения, а ожидание сообщения FD_CONNECT (которое в этом случае указывает на посылку соответствующего IGMP-сообщения) является одним из таких ограничений. Существует три случая, когда клиент может использовать WSPJoinLeaf.
- При работе в качестве многоточечного сервера (root) приглашает новый периферийный узел принять участие в сессии.
- При работе в качестве периферийного узла выполняется запрос подключения к корневой многоточечной сессии.
- При работе в качестве периферийного узла запрашивается подключение к некорневой многоточечной сессии (например, при IP-мультикастинге).
Как было упомянуто ранее, WSPJoinLeaf используется для присоединения периферийного узла к многоточечной сессии. WSPJoinLeaf имеет те же параметры и семантику, что и WSPConnect, за исключением того, что он возвращает дескриптор сокета (как и WSPAccept ), и имеет дополнительный параметр dwFlags. Параметр dwFlags показывает, будет ли сокет работать только в режиме чтения, только в режиме записи или в обоих режимах. Только многоточечный сокет может использоваться в качестве входного параметра s этой процедуры. Если многоточечный сокет находится в неблокирующем состоянии, полученный дескриптор сокета нельзя будет использовать до тех пор, пока не будет получено сообщение FD_CONNECT. Корневое приложение в многоточечной сессии может вызвать WSPJoinLeaf один или более раз, чтобы добавить новые узлы к текущей многоточечной сессии.
Параметры дескриптора сокета, присланного WSPJoinLeaf, варьируются в зависимости от того, является ли дескриптор c_root или c_leaf. Для c_root сокета параметр name означает имя определенного периферийного узла, который должен быть добавлен, а возвращенный дескриптор сокета является c_leaf и соответствует вновь добавленному периферийному узлу. Некоторые многоточечные приложения могут позволять этому сокету "постороннее" общение с корневым сервером.
При вызове WSPJoinLeaf для сокета c_leaf, параметр name содержит адрес корневого приложения (для схемы корневого управления) или существующей многоточечной сессии (некорневая схема управления), и возвращенный дескриптор сокета является тождественным по отношению ко входному дескриптору сокета. В корневой схеме управления корневой клиент должен поставить свой c_root сокет в режим ожидания с помощью WSPListen. При запросе периферийного узла о присоединении к группе присылается стандартное сообщение FD_ACCEPT. Корневой клиент использует для подключения нового периферийного узла обычную процедуру WSPAccept. Запрос WSPAccept присылает дескриптор сокета c_leaf, точно так же, как и WSPJoinLeaf.
Многоточечный корневой клиент является ответственным за прерывание сессии. Такое приложение может применить WSPShutdown или WSPClosesocket для сокета c_root, чтобы прислать всем членам группы сокетов c_leaf сообщение FD_CLOSE.
Рассмотрим семантическое отличие многоточечных и обычных сокетов. В плоскости управления имеется существенное семантическое отличие между сокетами c_root и обычными сокетами точка-точка.
- Сокет c_root может использоваться в процедуре WSPJoinLeaf для подключения новых периферийных узлов.
- Постановка сокета c_root в режим ожидания (путем вызова WSPListen ) не препятствует тому, чтобы сокет c_root применялся оператором WSPJoinLeaf для добавления в список участников нового периферийного узла или для посылки или получения информации.
- Закрытие сокета c_root вызовет отправку всем сопряженным сокетам c_leaf сообщения FD_CLOSE.
Не существует какого-либо семантического различия между сокетом c_leaf и традиционным сокетом в плоскости управления, за исключением того, что сокет c_leaf может использоваться процедурой WSPJoinLeaf, а использование сокета c_leaf в WSPListen указывает на то, что должны восприниматься только запросы многоточечного соединения.
В плоскости данных семантическое отличие между сокетами d_root и традиционными сокетами заключается в следующем:
- данные, посланные на сокет d_root, будут доставлены всем членам группы узлов, участвующих в многоточечном обмене;
- данные, полученные сокетом d_root, могут поступить от любого участника многоточечного обмена.
Сокет d_leaf в корневой плоскости данных не имеет каких-либо семантических отличий от традиционных сокетов, однако в некорневой плоскости данных информация, посланная на сокет d_lea f, поступит ко всем периферийным узлам группы. Данные могут передаваться любым участником многоточечной сессии. Информация о том, находится ли сокет d_leaf в корневой или некорневой плоскости данных, хранится в структуре сокета WSAPROTOCOL_INFO.
Следует иметь в виду, что перед написанием программы, использующей технологию сокетов, нужно сначала познакомиться с описанием библиотеки, которую вы собираетесь использовать.