Шрифт:
Для создания именованного канала сервер использует Windows-функцию CreateNamedPipe. Одним из входных параметров этой функции является указатель на имя канала в форме \\.\Рiре\ИмяКанала, где «\\.\» — псевдоним локального компьютера, определенный в Windows. Функция также принимает необязательный дескриптор защиты, запрещающий несанкционированный доступ к именованному каналу, флаг, указывающий, должен ли канал быть двусторонним или односторонним, параметр, определяющий максимальное число одновременных соединений по данному каналу, и флаг режима работы канала (побайтовой передачи или передачи сообщений).
Большинство сетевых API-функций работают только в режиме побайтовой передачи. Это означает, что переданное сообщение может быть принято адресатом в виде нескольких фрагментов, из которых воссоздается полное сообщение. Именованные каналы, работающие в режиме передачи сообщений, упрощают реализацию приемника, поскольку в этом случае число передач и приемов одинаково, а приемник, разом получая целое сообщение, не должен заботиться об отслеживании фрагментов сообщений.
При первом вызове CreateNamedPipe с указанием какого-либо имени создается первый экземпляр именованного канала с этим именем и задается поведение всех последующих экземпляров этого канала. Повторно вызывая CreateNamedPipe, сервер может создавать дополнительные экземпляры именованного канала, максимальное число которых указывается при первом вызове CreateNamedPipe. Создав минимум один экземпляр именованного канала, сервер выполняет Windows-функцию ConnectNamedPipe, после чего именованный канал позволяет устанавливать соединения с клиентами. Функция ConnectNamedPipe может выполняться как синхронно, так и асинхронно, и она не завершится, пока клиент не установит соединение через данный экземпляр именованного канала (или не возникнет ошибка).
Для подключения к серверу клиенты именованного канала используют Windows-функцию CreateFile или CallNamedPipe, указывая при вызове имя созданного сервером канала. Если сервер вызывает функцию ConnectNamedPipe, профиль защиты клиента и запрошенные им права доступа к каналу (для чтения или записи) сравниваются с дескриптором защиты канала (подробнее об алгоритмах проверки прав доступа см. главу 8). Если клиенту разрешен доступ к именованному каналу, он получает описатель, представляющий клиентскую сторону именованного канала, и функция ConnectNamedPipe, вызванная сервером, завершается.
После того как соединение по именованному каналу установлено, клиент и сервер могут использовать его для чтения и записи данных через Windows-функции ReadFile и WriteFile. Именованные каналы поддерживают как синхронную, так и асинхронную передачу сообщений. Взаимодействие клиента и сервера через именованный канал показано на рис. 13-9.
Уникальная особенность API именованного канала заключается в том, что он позволяет серверу олицетворять клиент с помощью функции ImpersonateNamedPipeClient. O том, как используется олицетворение в клиент-серверных приложениях, см. раздел «Олицетворение» главы 8.
Почтовые ящики предоставляют механизм ненадежного одностороннего широковещания. Одним из примеров приложений, использующих этот тип коммуникационной связи, является сервис синхронизации времени, который каждые несколько секунд широковещательно рассылает в пределах домена сообщение с эталонным временем. Такие сообщения не критичны для работы компьютеров в сети, поэтому они рассылаются через почтовые ящики.
Как и именованные каналы, почтовые ящики интегрированы с Windows API. Сервер почтового ящика создает почтовый ящик вызовом CreateMailslot. Входным параметром этой функции является имя в форме «\\.\Mailslot\ИмяПочтовогоЯщика». Сервер может создавать почтовые ящики только на той машине, на которой он работает, а назначаемые им имена почтовых ящиков могут включать подкаталоги. CreateMailslot также принимает необязательный дескриптор защиты, контролирующий доступ клиента к почтовому ящику. Описатели, возвращаемые CreateMailslot, являются перекрытыми.
Это означает, что операции с использованием таких описателей (например, рассылка и получение сообщений) выполняются асинхронно.
Поскольку почтовые ящики поддерживают одностороннюю ненадежную передачу, число параметров CreateMailslot меньше, чем у CreateNamedPipe. После создания почтового ящика сервер просто отслеживает поступающие клиентские сообщения, вызывая функцию ReadFile и указывая описатель, представляющий почтовый ящик.
Клиенты почтового ящика используют формат именования, аналогичный применяемому клиентами именованных каналов, за исключением вариаций, необходимых для широковещательной передачи сообщений всем почтовым ящикам с данным именем в домене клиента или в другом указанном домене. Чтобы послать сообщение в определенный экземпляр почтового ящика, клиент вызывает функцию CreateFile, указывая имя, специфичное для компьютера, например «\\Сервер\Mailslot\ИмяПочтовогоЯщика». (Для представления локального компьютера клиент задает «\\.\».) Если клиент хочет получить описатель, представляющий все почтовые ящики с заданным именем в домене, членом которого он является, он указывает имя в формате «\\*\Mailslot\ ИмяПочтовогоЯщика». Для широковещательной передачи во все почтовые ящики с заданным именем в другом домене используется имя в формате «\\ИмяДомена\Mailslot\ИмяПочтовогоЯщика».
Получив описатель, представляющий клиентскую сторону почтового ящика, клиент посылает сообщения через функцию WriteFile. Реализация почтовых ящиков допускает широковещательную передачу сообщений длиной не более 425 байтов. Если длина сообщения превышает 425 байтов, почтовый ящик использует механизм надежной коммуникационной связи, требующий соединения клиента с сервером по типу «один к одному», что исключает возможность широковещательной передачи. Другая (довольно странная) особенность почтовых ящиков — урезание сообщений с исходной длиной в 425 или 426 байтов до 424 байтов. Таким образом, почтовые ящики непригодны для рассылки сообщений, длина которых превышает 424 байта. Ha рис. 13–10 показан пример широковещательной передачи клиентского сообщения на несколько серверов почтовых ящиков в пределах домена.