Поименованные каналы
Поименованные каналы используют концепцию клиент-сервер. Приложение, создающее объект-поименованный канал, является сервером или серверным процессом, приложение, открывающее созданный объект-поименованный канал - клиентом (клиентским процессом).
Имена каналов в общем случае имеют следующий вид:
\\ИмяСервера\pipe\ИмяКанала
Если процесс открывает канал, созданный на другом ПК, он должен указать имя сетевое имя этго ПК. Если же процесс создает канал или открывает канал на своей рабочей станции, вместо имени указывается символ точки:
\\.\pipe\ИмяКанала
В любом случае процесс может создать канал только на той рабочей станции, где он запущен, поэтому при создании канала имя сервера никогда не указывается.
В простейшем случае один серверный процесс создает один канал (принято говорить 'одну реализацию канала') для работы с одним клиентским процессом. Однако часто требуется организовать взаимодействие одного серверного процесса с несколькими клиентскими. Например, сервер базы данных может принимать от клиентов запросы и рассылать ответы на них. В этом случае серверный процесс может создать несколько реализаций канала, по одной реализации для каждого клиентского процесса.
Создание поименованных каналов
Для создания именованного канала на стороне сервера следует использовать функцию CreateNamedPipe, имеющую прототип:
HANDLE CreateNamedPipe(
LPCTSTR lpName, // строка с именем канала
DWORD dwOpenMode, // режим открытия канала
DWORD dwPipeMode, // режим работы канала
DWORD nMaxInstances, // максимальное количество реализаций // канала
DWORD nOutBufferSize, // размер выходного буфера в байтах
DWORD nInBufferSize, // размер входного буфера в байтах
|
DWORD nDefaultTimeOut, // время ожидания в миллисекундах
LPSECURITY_ATTRIBUTES lpSecurityAttributes); // адрес
// переменной для атрибутов защиты
Параметры:
1) lpName
Через параметр lpName передается адрес строки имени канала в форме \\.\pipe\ИмяКанала (при создании канала имя сервера не указывается, так как канал можно создать только на той рабочей станции, где запущен создающий серверный процесс).
2) dwOpenMode
Канал Pipe может быть ориентирован либо на передачу потока байт, либо на передачу сообщений. В первом случае данные через канал передаются по байтам, во втором - отдельными блоками заданной длины. Режим работы канала (ориентированный на передачу байтов или сообщений) задается, соответственно, константами PIPE_TYPE_BYTE или PIPE_TYPE_MESSAGE, которые указываются в параметре dwOpenMode. По умолчанию - PIPE_TYPE_BYTE.
Помимо способа передачи данных через канал с помощью этого же параметра dwOpenMode можно указать способ использования канала:
- только для чтения данных,
- только для записи,
- одновременно для чтения и записи.
Способ использования канала задается константами из таблиц 1, 2. Параметры из таблицы 1 должны быть одинаковы для всех реализаций канала, параметры из таблицы 2 могут различаться для разных реализаций канала (дл разных клиентских процессовов).
Таблица 1
Константа | Использование канала | |||
PIPE_ACCESS_INBOUND | Только для чтения | |||
PIPE_ACCESS_OUTBOUND | Только для записи | |||
PIPE_ACCESS_DUPLEX | Для чтения и записи | |||
Таблица 2
Константа | Использование канала | |||
PIPE_READMODE_BYTE | Канал открывается на чтение в режиме последовательной передачи отдельных байтов | |||
PIPE_READMODE_MESSAGE | Канал открывается на чтение в режиме передачи отдельных сообщений указанной длины | |||
PIPE_WAIT | Канал будет работать в блокирующем режиме, когда процесс переводится в состояние ожидания завершения операций в канале | |||
PIPE_NOWAIT | Неблокирующий режим работы канала. Если операция не может быть выполнена немедленно, в неблокирующем режиме функция завершается с ошибкой | |||
FILE_FLAG_OVERLAPPED | Использование асинхронных операций (ввод и вывод с перекрытием). Данный режим позволяет процессу выполнять другие действия параллельно с проведением операций в канале | |||
FILE_FLAG_WRITE_THROUGH | В этом режиме функции, работающие с каналом, не возвращают управление до тех пор, пока не будет полностью завершена операция на удаленном компьютере. Используется только с каналом, ориентированном на передачу отдельных байт и только в том случае, когда канал создан между процессами, запущенными на различных станциях сети | |||
|
Дополнительно к перечисленным выше флагам, через параметр dwOpenMode можно передавать следующие флаги защиты:
Флаг | Описание | |||
WRITE_DAC | Вызывающий процесс должен иметь права доступа на запись к произвольному управляющему списку доступа именованного канала access control list (ACL) | |||
WRITE_OWNER | Вызывающий процесс должен иметь права доступа на запись к процессу, владеющему именованным каналом Pipe | |||
ACCESS_SYSTEM_SECURITY | Вызывающий процесс должен иметь права доступа на запись к управляющему списку доступа именованного канала access control list (ACL) | |||
3) dwPipeMode
Теперь перейдем к параметру dwPipeMode, определяющему режим работы канала. В этом параметре можно указать перечисленные выше константы
|
PIPE_TYPE_BYTE,
PIPE_TYPE_MESSAGE,
PIPE_READMODE_BYTE,
PIPE_READMODE_MESSAGE,
PIPE_WAIT и
PIPE_NOWAIT.
Для всех реализаций канала необходимо указывать один и тот же набор констант.
4) nMaxInstances
Параметр nMaxInstances определяет максимальное количество реализаций, которые могут быть созданы для канала. Вы можете указывать здесь значения от 1 до PIPE_UNLIMITED_INSTANCES. В последнем случае максимальное количество реализаций ограничивается только наличием свободных системных ресурсов.
Заметим, что если один серверный процесс использует несколько реализаций канала для связи с несколькими клиенсткими процессами, то общее количество реализаций может быть меньше, чем потенциальное максимальное количество клиентов. Это связано с тем, что клиенты могут использовать одну и ту же реализацию по очереди, если только не пожелают связаться с серверным процессом все одновременно.
5) nOutBufferSize и nInBufferSize nMaxInstances
Параметры nOutBufferSize и nInBufferSize определяют, соответственно, размер буферов, используемых для записи данных в канал и чтения из канала.
6) nDefaultTimeOut
Параметр nDefaultTimeOut определяет время ожидания открытия канала. Для всех реализаций необходимо указывать одинаковое значение этого параметра.
7) lpPipeAttribute
Через параметр lpPipeAttributes передается адрес переменной, содержащей атрибуты защиты для создаваемого канала. В данных приложениях будем указывать этот параметр как NULL. В результате канал будет иметь атрибуты защиты, принятые по умолчанию.
В случае успеха функция CreateNamedPipe возвращает дескриптор одной созданной реализации канала, который можно использовать в операциях чтения и записи, выполняемых с помощью таких функций, как ReadFile и WriteFile.
При ошибке функция CreateNamedPipe возвращает значение INVALID_HANDLE_VALUE. Для уточнения кода ошибки вызывается функция GetLastError.
На стороне клиента для открытия существующий реализации поиенованного канала используют функцию CreateFile(). При этом вместо имени файла следует указать имя канала.
По окончании работы с каналом клиенский процесс должен отключиться от серверного процесса и закрыть канал с помощью функции
CloseHandle(hNamedPipe),
где аргумент - дескриптор канала, который вернула функция CreateFile(). Серверный процесс также закрывает канал с помощью этой же функции, но аргумент - дескриптор канала, который вернула функция CreateCreateNamedPipe().
Пример
LPTSTR lpszPipename = "\\\\.\\pipe\\mypipe";
DWORD bufSize = 1024;
HANDLE hPipe = CreateNamedPipe(
lpszPipename, // имя канала
PIPE_ACCESS_DUPLEX, // чтение/запись
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
//передаются сообщения,
//Канал открывается на чтение в режиме передачи
//отдельных сообщений указанной длины
//Канал будет работать в блокирующем режиме
PIPE_UNLIMITED_INSTANCES, // число реализаций
bufSize, //размер вых буфера
bufSize, //размер вход.буфера
NMPWAIT_USE_DEFAULT_WAIT, // ожидание по умолчанию
NULL // атриб. безопасности
);
if (hPipe == INVALID_HANDLE_VALUE)
{ printf("Не могу создать канал\n");
}