Скачиваний:
14
Добавлен:
01.05.2014
Размер:
317.44 Кб
Скачать

2. Именованные каналы

Именованные каналы предоставляют приложениям надежную двухстороннюю связь. Именованный канал создается вызовом:

NP = CreateNamedPipe("\\\\.\\pipe\\mypipe",

PIPE_ACCESS_DUPLEX,

PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT,

1,

0,

0,

INFINITE,

NULL);

Машина, создавшая такой канал, становится сервером. Сервер переходит в режим ожидания запросов клиента с помощью вызова:

ConnectNamedPipe(NP, NULL);

Поскольку вызов функции ConnectNamedPipe() приводит к ожиданию процесса, то лучше ее вызывать в отдельном потоке.

Клиент подключается к каналу с помощью вызова:

NP = CreateFile("\\\\pc_name\\pipe\\mypipe",

GENERIC_READ|GENERIC_WRITE,

0,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL,

NULL);

После того, как соединение между сервером и клиентом будет установлено, они могут обмениваться данными с помощью вызовов ReadFile() и WriteFile(), аналогично предыдущему случаю.

Аналогичным образом (CloseHandle()) канал закрывается.

Здесь уместно рассказать более подробно об асинхронном вводе-выводе.

Основы асинхронного ввода-вывода

Существует два варианта ввода-вывода:

  1. Синхронный ввод-вывод, при котором поток, вызвавший эту операцию, блокируется до завершения

  2. Асинхронный ввод-вывод, при котором поток вызывает операцию ввода-вывода (ReadFile() или WriteFile()) и сразу же получает управление обратно. Операция ввода-вывода выполняется не зависимо от потока, но когда она завершается, поток узнает об этом с помощью дополнительных средств.

Существует три способа асинхронного ввода-вывода.

  1. Синхронный ввод-вывод в отдельном потоке. Самый простой и многими рекомендуемый способ. Программа продолжает выполняться в своем потоке, а ожидание завершения ввода-вывода происходит в дополнительном потоке.

  2. Ввод-вывод с перекрытием. В этом случае к операции ввода-вывода “привязывается” событие. Когда операция ввода-вывода начинается, процесс переходит к ожиданию этого события. При этом ожидание может выполняться без блокировки. Когда операция ввода-вывода завершается, событие взводится и сигнализирует процессу о своем завершении.

  3. Ввод-вывод с процедурой завершения. К операции ввода-“привязывается” специальная процедура, которая вызывается операционной системой, когда операция завершается. В начале работы операционной системе надо передать адрес этой процедуры. Внутри процедуры можно взводить, например, некоторый флаг, установка которого говорит о том, что операция завершилась.

Про первый вариант говорить не будем, т.к. он использует традиционный вариант вызовов ReadFile() и WriteFile().

Про третий вариант поговорим, когда будем рассматривать протокол NetBIOS.

На данном этапе рассмотрим второй вариант, при этом для конкретности рассмотрим его применительно к именованным каналам.

Первое, что нужно сделать, это создавать объект (в данном случае, именованный канал) с флагом FILE_FLAG_OVERLAPPED.

NP = CreateNamedPipe("\\\\.\\pipe\\mypipe",

PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,...

В операции ввода-вывода последним параметром передается указатель на специальную структуру данных, которая называется структурой перекрытия.

OVERLAPPED OverLap;

Обычно в качестве последнего параметра передается NULL, что указывает на синхронный ввод-вывод.

ReadFile(hPipe, buffer, BUF_SIZE, &NumberOfBytesRead, &OverLap);

Если такая структура передана в вызов, то операция ReadFile() завершается сразу же. Т.е. как бы дается команда “начать ввод-вывод”. За состоянием ввода-вывода можно следить теперь, получая информацию из этой структуры.

Как выглядит структура перекрытия:

typedef struct _OVERLAPPED

DWORD Internal; //резервируется ОС

DWORD InternalHigh; //резервируется ОС

DWORD Offset; //используется при вводе-выводе с дисковыми файлами

DWORD OffsetHigh; // используется при вводе-выводе с дисковыми файлами

HANDLE hEvent; //

} OVERLAPPED

Для коммуникационных устройств типа COM-портов и именованных каналов большинство параметров не используются.

Для нас важно, что в эту структуру входит событие hEvent.

Событие надо создать вызовом:

OverLap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES lpEventAttributes, // pointer to security attributes

BOOL bManualReset, // flag for manual-reset event

BOOL bInitialState, // flag for initial state

LPCTSTR lpName // pointer to event-object name

);

После выполнения операции ReadFile() необходимо перейти к ожиданию события OverLap.hEvent, сигнализирующего о завершении операции ввода-вывода.

WaitForSingleObject(OverLap.hEvent, TIME_OUT);

DWORD WaitForSingleObject(

HANDLE hHandle, // handle to object to wait for

DWORD dwMilliseconds // time-out interval in milliseconds

);

Значение параметра TIME_OUT может варьироваться от 0 до INFINITE. При значении 0 функция сразу же завершится.

DWORD result;

while (1) {

result = WaitForSingleObject(OverLap.hEvent, TIME_OUT);

if (WAIT_TIMEOUT == result){

// do something

continue;

}else if (WAIT_OBJECT_0 == result) {

break;

}

}

Когда операция ввода-вывода завершится, процесс выйдет из цикла по break-у, и тогда можно узнать количество реально переданных данных.

Это делается операцией:

DWORD bytesTrans;

GetOverlappedResult(hPipe, &OverLap, &bytesTrans, FALSE);

BOOL GetOverlappedResult(

HANDLE hFile, // handle to file, pipe, or comm device

LPOVERLAPPED lpOverlapped, // pointer to overlapped structure

LPDWORD lpNumberOfBytesTransferred, // pointer to actual bytes count

BOOL bWait // wait flag

);

Т.е. в буфере buffer находится bytesTrans вновь полученных байтов.

Подводя итог, перечислим этапы ввода-вывода с перекрытием:

  1. Создать объект с флагом: FILE_FLAG_OVERLAPPED;

  2. Создать структуру перекрытия: OVERLAPPED OverLap;

  3. Создать событие в этой структуре: OverLap.hEvent = CreateEvent(…);

  4. Вызвать функцию ввода-вывода: ReadFile(…, &OverLap);

  5. Перейти к ожиданию события: WaitForSingleObject(OverLap.hEvent);

  6. При наступлении события узнать количество принятых байтов вызовом GetOverlappedResult()

В заключении материала об асинхронном вводе-выводе следует отметить сложность реализации такого способа ввода-вывода.

Соседние файлы в папке Материалы к курсу