
- •1. Каналы. Именованные и анонимные каналы. Назначение. Области применения
- •2.Использование анонимных каналов
- •3. Использование именованных каналов
- •3.1. Серверная сторона именованных каналов
- •3.2. Клиентская сторона именованных каналов
- •3.3. Решения при разработке сервера именованного канала
- •4. Порядок выполнения работы
- •5.Контрольные вопросы
- •Приложения
- •1.Пример многопоточного сервера
- •2.Пример клиента
- •3.Использование дополнительных функций
- •4.Пример сервера с асинхронным вводом – выводом
- •5.Пример сервера с процедурами завершения
4.Пример сервера с асинхронным вводом – выводом
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#define CONNECTING_STATE 0
#define READING_STATE 1
#define WRITING_STATE 2
#define INSTANCES 4
#define BUFSIZE 200
#define PIPE_TIMEOUT 200
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
CHAR chBuf[BUFSIZE];
DWORD cbToWrite;
DWORD dwState;
BOOL fPendingIO;
} PIPEINST, *LPPIPEINST;
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetDataToWriteToClient(LPPIPEINST pPipe)
{
lstrcpy(pPipe->chBuf,"hi to all!");
pPipe->cbToWrite = lstrlen(pPipe->chBuf) + 1;
}
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
int main(int argc, char* argv[])
{
DWORD i, dwWait, cbBytes, dwErr;
BOOL fSuccess;
LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";
// Цикл инициализации - создает несколько экземпляров
// именнованных каналов
// Асинхронная операция ConnectNamedPipe
// запускается для каждого экземпляра
for (i = 0; i < INSTANCES; i++)
{
// Создание объекта события для экземпляра - канала
hEvents[i] = CreateEvent(
NULL, // no security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (hEvents[i] == NULL)
{
printf("CreateEvent Error");
exit(1);
}
Pipe[i].oOverlap.hEvent = hEvents[i];
Pipe[i].hPipeInst = CreateNamedPipe(
lpszPipename, // название канала
PIPE_ACCESS_DUPLEX | // доступ на чтение - запись
FILE_FLAG_OVERLAPPED, // асинхронный ружим
PIPE_TYPE_MESSAGE | // тип канала - обмен сообщениями
PIPE_READMODE_MESSAGE | // режим - чтения сообщений
PIPE_WAIT, // блокирующий режим
INSTANCES, // максисмальное количество экземпляров
BUFSIZE, // размер выходного буфера
BUFSIZE, // размер входного буфера
PIPE_TIMEOUT, // тайм - аут клиента
NULL); // без атрибутов безопасности
if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)
{
printf("CreatePipe Error");
exit(1);
}
// посоединение нового клиента
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
CONNECTING_STATE : // в состоянии соединения ?
READING_STATE; // готов к чтению
}
while (1)
{
// Ожидание установки события - означающее
// окончания асинхронного чтения, записи или операции соединения
dwWait = WaitForMultipleObjects(
INSTANCES, // количество объектов событий
hEvents, // массив объектов событий
FALSE, // не ждать всех
INFINITE); // ожидание бексонечно
// dwWait - показывает какой канал завершил операцию.
i = dwWait - WAIT_OBJECT_0; // определяем номер канала
if (i < 0 || i > (INSTANCES - 1))
{
printf("Index out of range");
exit(1);
}
// получить результат если операция не завершена.
if (Pipe[i].fPendingIO)
{
fSuccess = GetOverlappedResult(
Pipe[i].hPipeInst, // дескриптор канала
&Pipe[i].oOverlap, // OVERLAPPED структура
&cbBytes, // байт перенесено
FALSE); // не ждать завершения операции
switch (Pipe[i].dwState)
{
// выполняется операция соединения
case CONNECTING_STATE:
if (! fSuccess)
printf("ConnectNamedPipe Error");
Pipe[i].dwState = READING_STATE;
break;
// выполняется операция чтения
case READING_STATE:
if (! fSuccess || cbBytes == 0)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].dwState = WRITING_STATE;
break;
// выполняется операция записи
case WRITING_STATE:
if (! fSuccess || cbBytes != Pipe[i].cbToWrite)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].dwState = READING_STATE;
break;
default:
printf("Invalid pipe state");
exit(1);
}
}
// состояние канала определяет следующую операцию
switch (Pipe[i].dwState)
{
// READING_STATE:
// Экземпляр канала соединен с клиентом и готов
// прочесть запрос от клиента
case READING_STATE:
fSuccess = ReadFile(
Pipe[i].hPipeInst,
Pipe[i].chBuf,
BUFSIZE,
&cbBytes,
&Pipe[i].oOverlap);
// Операция чтения завершена успешна.
if (fSuccess && cbBytes != 0)
{
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = WRITING_STATE;
continue;
}
// Операция чтения не завершена.
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING))
{
Pipe[i].fPendingIO = TRUE;
continue;
}
// Произошла ошибка; отсоединить от клиента.
DisconnectAndReconnect(i);
break;
// WRITING_STATE:
// Запрос был успешно прочитан (получен) от клиента
// Получить данные для ответа и записать (послать) в клиента
case WRITING_STATE:
GetDataToWriteToClient(&Pipe[i]);
fSuccess = WriteFile(
Pipe[i].hPipeInst,
Pipe[i].chBuf,
Pipe[i].cbToWrite,
&cbBytes,
&Pipe[i].oOverlap);
// Операция записи завершена успешно.
if (fSuccess && cbBytes == Pipe[i].cbToWrite)
{
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = READING_STATE;
continue;
}
// Операция записи не завершена.
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING))
{
Pipe[i].fPendingIO = TRUE;
continue;
}
// Произошла ошибка; отсоединить от клиента.
DisconnectAndReconnect(i);
break;
default:
printf("Invalid pipe state");
exit(1);
}
}
return 0;
}
// Функция вызывается при ошибки или когда клиент закрывает соединение
// (свой дескриптор к каналу). Отсоединиться от данного клиента, затем вызвать
// ConnectNamedPipe для ожидания подсоединения другог клиента
VOID DisconnectAndReconnect(DWORD i)
{
//Отсоединить экземпляр канала.
if (! DisconnectNamedPipe(Pipe[i].hPipeInst) )
{
printf("DisconnectNamedPipe Error");
exit(1);
}
// Подсоединение нового клиента.
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
CONNECTING_STATE : // в процессе соединения
READING_STATE; // готов к чтению
}
// Функция вызывается для запуска асинхронной операции соединения
// Возвращает TRUE если операция в процессе выполнения и
// FALSE если соединение установлено
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL fConnected, fPendingIO = FALSE;
// Запуск асинхронного соединения для данного экземпляра канала.
fConnected = ConnectNamedPipe(hPipe, lpo);
// Асинхронная функция ConnectNamedPipe должа возвращать ноль.
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;
}