
- •1. Каналы. Именованные и анонимные каналы. Назначение. Области применения
- •2.Использование анонимных каналов
- •3. Использование именованных каналов
- •3.1. Серверная сторона именованных каналов
- •3.2. Клиентская сторона именованных каналов
- •3.3. Решения при разработке сервера именованного канала
- •4. Порядок выполнения работы
- •5.Контрольные вопросы
- •Приложения
- •1.Пример многопоточного сервера
- •2.Пример клиента
- •3.Использование дополнительных функций
- •4.Пример сервера с асинхронным вводом – выводом
- •5.Пример сервера с процедурами завершения
5.Пример сервера с процедурами завершения
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 200
#define PIPE_TIMEOUT 100
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
CHAR chBuf[BUFSIZE];
DWORD cbToWrite;
} PIPEINST, *LPPIPEINST;
BOOL CreateAndConnectInstance(OVERLAPPED*);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetDataToWriteToClient(LPPIPEINST);
VOID DisconnectAndClose(LPPIPEINST);
VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
HANDLE hPipe;
DWORD main(VOID)
{
HANDLE hConnectEvent;
OVERLAPPED oConnect;
LPPIPEINST lpPipeInst;
DWORD dwWait, cbBytes;
BOOL fSuccess, fPendingIO;
// Создание объекта события для операции соединения.
hConnectEvent = CreateEvent(
NULL, // no security attribute
TRUE, // manual reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (hConnectEvent == NULL)
{
printf("CreateEvent Error!");
exit(1);
}
oConnect.hEvent = hConnectEvent;
// Вызов подпрограммы для создания одного экземпляра канала и
// ожидания подсоединения клиента.
fPendingIO = CreateAndConnectInstance(&oConnect);
while (1)
{
// Ожидание подсоединения клиента, или завершения операций
// для чтения или записи,которая ставит в очередь выполнение
// процедуры завершения
//
dwWait = WaitForSingleObjectEx(
hConnectEvent, // событие которое ожидается
INFINITE, // ждать бесконечно
TRUE); // для выполнения процедур завершения
switch (dwWait)
{
case 0:
// Если операция не завершена - получить результат
// операции подсоединения
if (fPendingIO)
{
fSuccess = GetOverlappedResult(
hPipe, // дескриптор канала
&oConnect, // OVERLAPPED структура
&cbBytes, // количество перенесенных байт
FALSE); // без ожидания
if (!fSuccess)
{
printf("ConnectNamedPipe Error!");
exit(1);
}
}
// Выделить память под экземпляр.
lpPipeInst = (LPPIPEINST) GlobalAlloc(
GPTR, sizeof(PIPEINST));
if (lpPipeInst == NULL)
{
printf("GlobalAlloc lpPipeInst Error!");
exit(1);
}
lpPipeInst->hPipeInst = hPipe;
// Запуск операции чтения для данного клиента
// Та же самая подпрограмма вызывается после
// операции записи как подпрограмма завершения операции
lpPipeInst->cbToWrite = 0;
CompletedWriteRoutine(0, 0, (LPOVERLAPPED) lpPipeInst);
// Создание нового экземпляра канала для следующего клиента.
fPendingIO = CreateAndConnectInstance(
&oConnect);
break;
// Ожидание заканчивается при завершении операции чтения или
// записи. Это позволяет системе использовать подпрограмму завершения
case WAIT_IO_COMPLETION:
break;
// Произошла ошибка в функции ожидания.
default:
printf("WaitForSingleObjectEx Error");
exit(1);
}
}
return 0;
}
// Это подпрограмма вызывается как процедура завершения после записи в канал,
// или когда новый клиент подсоединился к экземпляру.
// Запускается новая операция чтения
VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten,
LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fRead = FALSE;
// lpOverlap указывает на память для экземпляра
lpPipeInst = (LPPIPEINST) lpOverLap;
// Операция записи завершена, поэтому читаем следующий запрос
// (если нет ошибок).
if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite))
fRead = ReadFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chBuf,
BUFSIZE,
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
// Отсоединение если произошла ошибка
if (! fRead)
DisconnectAndClose(lpPipeInst);
}
// Данная подпрограмма вызыввается, как процедура завершения после чтения
// запроса от клиента. Получает данные и записывает в канал.
VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead,
LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fWrite = FALSE;
// lpOverlap указывает на память для экземпляра.
lpPipeInst = (LPPIPEINST) lpOverLap;
// Операция чтения завершена, записать ответ (если не произошло ошибок)
if ((dwErr == 0) && (cbBytesRead != 0))
{
GetDataToWriteToClient(lpPipeInst);
fWrite = WriteFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chBuf,
lpPipeInst->cbToWrite,
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine);
}
// Отсоединение если произошла ошибка.
if (! fWrite)
DisconnectAndClose(lpPipeInst);
}
// Данная подпрограмма вызывается, если произошла ошибка
// или клиент закрывает дескриптор канала
VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
{
// Отсоединить экземпляр канала.
if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) )
{
printf("DisconnectNamedPipe Error!");
exit(1);
}
// Закрыть дескриптор канала.
CloseHandle(lpPipeInst->hPipeInst);
// Освободить память выделенную для канала
if (lpPipeInst != NULL)
GlobalFree(lpPipeInst);
}
// Данная функция создает экземпляр канала и соединяется с клиентом.
// Возвращает TRUE если операция соединения не завершена и FALSE, если
// соединение завершено.
BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
{
LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";
hPipe = CreateNamedPipe(
lpszPipename, // название канала
PIPE_ACCESS_DUPLEX | // доступ на чтение / запись
FILE_FLAG_OVERLAPPED, // асинхронный режим
PIPE_TYPE_MESSAGE | // канал для сообщений
PIPE_READMODE_MESSAGE | // режим чтения сообщений
PIPE_WAIT, // блокирующий режим
PIPE_UNLIMITED_INSTANCES, // бесконечное количество экземпляров
BUFSIZE, // размер выходного буфера
BUFSIZE, // размер входного буфера
PIPE_TIMEOUT, // тайм аут клиента
NULL); // нет атрибутов безопасности
if (hPipe == INVALID_HANDLE_VALUE)
{
printf("CreatePipe Error!");
exit(2);
}
// выхов процедуры для подсоединения нового клиента
return ConnectToNewClient(hPipe, lpoOverlap);
}
// Эта функция вызывается для запуска асинхронной операции соединения
// Возвращает TRUE если операция не завершена или FALSE если соединение установлено
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL fConnected, fPendingIO = FALSE;
// Запуск асинхронной операции соединения для данного экземпляра канала
fConnected = ConnectNamedPipe(hPipe, lpo);
// Асинхронный ConnectNamedPipe(hPipe, lpo) должен возвращать 0
if (fConnected)
{
printf("Connect NamedPipe Error");
exit(1);
}
switch (GetLastError())
{
// Асинхронное соединение в процессе выполнения.
case ERROR_IO_PENDING:
fPendingIO = TRUE;
break;
// Клиент подсоединен - установка события
case ERROR_PIPE_CONNECTED:
if (SetEvent(lpo->hEvent))
break;
// Если произошла ошибка во время операции соединения
default:
printf("ConnectNamedPipe Error");
exit(1);
}
return fPendingIO;
}
VOID GetDataToWriteToClient(LPPIPEINST pPipe)
{
lstrcpy(pPipe->chBuf,"hi to all!");
pPipe->cbToWrite = lstrlen(pPipe->chBuf) + 1;
}