После того как серверный процесс создал канал, он может перейти в режим соединения с клиентским процессом. Соединение со стороны сервера выполняется с помощью функции ConnectNamedPipe. Прототип которой представлен ниже:
BOOL ConnectNamedPipe(
HANDLE hNamedPipe, //идентификатор именованного канала
LPOVERLAPPED lpOverlapped); // адрес структуры OVERLAPPED
Первый параметр - дескриптор канала, полученный от функции CreateNamedPipe().
Второй параметр используется только для огранизации асинхронного обмена данными через канал. При использовании синхронныч операции значение этого параметра можно задать как NULL.
В случае успеха функция ConnectNamedPipe()возвращает значение TRUE, а при ошибке - FALSE. Код ошибки можно получить с помощью функции GelLastError().
Для канала, созданного в синхронном блокирующем режиме (т.е. с использованием константы PIPE_WAIT), функция ConnectNamedPipe() переводит серверный процесс в состояние ожидания соединения с клиентским процессом.
Если канал создан в синхронном неблокирующем режиме, функция ConnectNamedPipe() немедленно возвращает управление с кодом TRUE, если только клиент был отключен от данной реализации канала или не подключался ранее и возможно новое подключение этого клиента. В противном случае возвращается значение FALSE.
Дальнейший анализ необходимо выполнять с помощью функции GetLastError(). Эта функция может вернуть значение:
ERROR_PIPE_LISTENING - к серверу еще не подключен ни один клиент,
ERROR_PIPE_CONNECTED - клиент уже подключен к серверу,
ERROR_NO_DATA - предыдущий клиент отключился от сервера, но
клиент еще не закрыл соединение.
ПРИМЕР
BOOL fConnected;
fConnected = ConnectNamedPipe(hPipe, NULL);
//Ожидание клиента
if (!fConnected)
{ printf ("Ошибка при подключении клиента\n";
}
Установка соединения с каналом на стороне клиента
|
Для создания канала клиентский процесс может воспользоваться функцией CreateFile(), которая предназначена для работы с файлами,устройствами, каналами (подробно см. раздел ОС_Допол_Работа сфайлами.rtf).
В случае успешного завершения функция CreateFile() возвращает идентификатор созданного или открытого файла/каталога или канала.
При ошибке возвращается значение INVALID_HANDLE_VALUE. Код ошибки можно определить при помощи функции GetLastError().
В том случае, если файл уже существует и были указаны константы CREATE_ALWAYS или OPEN_ALWAYS, функция CreateFile() не возвращает код ошибки, но функция GetLastError() возвращает значение ERROR_ALREADY_EXISTS.
Функция WaitNamedPipe
С помощью функции WaitNamedPipe() процесс может выполнять ожидание момента, когда канал Pipe будет доступен для соединения:
BOOL WaitNamedPipe(
LPCTSTR lpszPipeName, // имя канала Pipe
DWORD dwTimeout); // время ожидания в миллисекундах
Помимо численного значения времени в миллисекундах, можно указать в этом параметре одну из следующих констант:
Константа | Описание | |||
NMPWAIT_WAIT_FOREVER | Ожидание выполняется бесконечно долго | |||
NMPWAIT_USE_DEFAULT_WAIT | Ожидание выполняется в течении периода времени, указанного при вызове функции CreateNamedPipe | |||
ПРИМЕР
HANDLE hPipe;
CHAR chBuf[512];
DWORD cbRead, cbWritten, dwMode;
LPTSTR lpPipename = "\\\\.\\pipe\\mypipe";
while (1) // Открытие поименованного канала
{ hPipe = CreateFile(
lpPipename, // pipe name
GENERIC_READ | GENERIC_WRITE,// доступ на чтение/запись
0, // нет разрешений для других
// процессов
NULL, // атрибуты безопасности
OPEN_EXISTING, // открыть уже существ. канал
0, // флаги и атрибуты по умолч.
|
NULL // нет файла-шаблона
);
if (hPipe == INVALID_HANDLE_VALUE)
{ printf ("hPipe = INVALID_HANDLE_VALUE \n");
return;
}
if (GetLastError()!= ERROR_PIPE_BUSY)
{ printf ("Не могу открыть канал \n");
return;
// Выход, если ошибка!=ERROR_PIPE_BUSY(канал занят)
}
// Если все реализации канала заняты, ждем 30 секунд, затем // опять выполняем попытку соединения.
if (!WaitNamedPipe(lpPipename, 30000))
{ printf ("Не могу открыть канал в течение 30 сек\n";
}
}
5. Запись данных в канал и чтение данных из канала
Запись данных в открытый канал выполняется с помощью функции WriteFile(), аналогично записи в обычный файл, например:
HANDLE hNamedPipe;
DWORD cbWritten;
char Buf1[256];
WriteFile (hNamedPipe, szBuf, strlen(szBuf) + 1, &cbWritten, NULL);
параметр cbWritten используется для определения количества байт данных, действительно записанных в канал. И, наконец, последний параметр задан как NULL, поэтому запись будет выполняться в синхронном режиме. Если канал был создан для работы в блокирующем режиме, и функция WriteFile работает синхронно (без использования вывода с перекрытием), то эта функция не вернет управление до тех пор, пока данные не будут записаны в канал.
Чтение данных из канала выполняется функцией ReadFile():
HANDLE hNamedPipe;
DWORD cbRead;
char Buf1[256];
ReadFile (hNamedPipe, szBuf, 512, &cbRead, NULL);
Данные, прочитанные из канала hNamedPipe, будут записаны в буфер szBuf, имеющий размер 512 байт. Количество действительно прочитанных байт данных будет сохранено функцией ReadFile в переменной cbRead. Так как последний параметр функции указан как NULL, используется синхронный режим работы без перекрытия.
Обычно сценарий взаимодействия клиентского процесса с серверным заключается в выполнении следующих операций:
- подключение к каналу с помощью функции CreateFile;
- выполнение операций чтения или записи такими функциями как ReadFile или WriteFile;
- отключение от канала функцией CloseHandle.