Вы находитесь на странице: 1из 6

Дополнительные материалы

Использование каналов для передачи данных между


процессами

Анонимные каналы

Однонаправленная передача данных между процессами с


использованием анонимного канала

Пример. Родительский процесс (приложение Parent1.exe)


создает анонимный канал, затем – дочерний процесс
(приложение Child1.exe) с передачей ему дескриптора
чтения канала. Затем первый процесс записывает в канал
блок данных с адресом lpData и размером dwSize байтов.
Дочерний процесс читает эти данные из канала и
обрабатывает их.
Файл Parent1.cpp - родительский процесс

PVOID lpData; // Адрес блока данных
// Размер блока данных и кол-во запис. байтов
DWORD dwSize, dwWritten;
…// Выделение памяти и заполнение блока данными
HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES PipeSA = {sizeof
(SECURITY_ATTRIBUTES), NULL, TRUE};
PROCESS_INFORMATION ProcInfo;
STARTUPINFO StartInfo;
// Создание анонимного канала
CreatePipe(&hReadPipe, &hWritePipe, &PipeSA, 0);
// Очистка структуры StartInfo
ZeroMemory(&StartInfo, sizeof(STARTUPINFO));
StartInfo.cb = sizeof(STARTUPINFO);
// Перенаправление стандартного ввода на канал
StartInfo.hStdInput = hReadPipe;
StartInfo.hStdError=GetStdHandle(STD_ERROR_HANDLE);
StartInfo.hStdOutput=GetStdHadle(STD_OUTPUT_HANDLE);
StartInfo.dwFlags = STARTF_USESTDHANDLES;
// Создание дочернего процесса
CreateProcess(NULL, "Child", NULL, NULL, TRUE, 0, NULL,
NULL, &StartInfo, &ProcInfo);
// Закрытие дескриптора канала для чтения
CloseHandle(hReadPipe);
// Запись данных в канал
for (; ;)
if (! WriteFile(hWritePipe, lpData, dwSize, &dwWritten, NULL))
break;
// Закрытие дескриптора канала для записи
CloseHandle(hWritePipe);

Файл Child1.cpp - дочерний процесс

// Адрес блока данных, получаемых из канала
PVOID lpData;
// Размер блока данных и кол-во прочит. байтов
DWORD dwSize, dwRead;
…// Выделение памяти для блока данных
HANDLE hStdIn; // Дескриптор уст-ва станд. ввода
BOOL fSuccess; // Флаг успешн. заверш. чтения
// Получение дескриптора канала для чтения
hStdIn = GetStdHandle(STD_INTPUT_HANDLE);
if (hStdIn == INVALID_HANDLE_VALUE)
ExitProcess(1);
// Чтение данных из канала
for (; ;)
{
fSuccess=ReadFile(hStdIn, lpData, dwSize, &dwRead, NULL);
if (! fSuccess || dwRead == 0)
break;
}
… // Обработка данных, прочитанных из канала
Примечание. Если необходимо передавать данные в
обратном направлении, то родительский процесс должен
перенаправить стандартный вывод дочернего процесса на
канал, а сам использовать дескриптор канала для чтения.

Именованные каналы
Однонаправленная передача данных между процессами с
использованием именованного канала
Рассмотрим использование описанных выше средств Win32
API для организации передачи данных от сервера к клиенту
на одном компьютере. Для этого, при создании канала
сервером с помощью функции CreateNamedPipe(),
параметру dwOpenMode задается значение
PIPE_ACCESS_OUTBOUND. Также, при открытии канала
клиентом с помощью функции CreateFile() параметру
dwDesiredAccess задается значение GENERIC_READ.
Приложение – сервер канала должно содержать
следующий код:

// Адрес блока передаваемых данных
PVOID lpSendData;
// Размер блока данных и кол-во запис. байтов
DWORD dwSize, dwWritten;
…// Выделение памяти и заполнение блока данными
HANDLE hNamedPipe; // Дескриптор канала
// Создание именованного канала
hNamedPipe = CreateNamedPipe("\\\\.\\pipe\\MyPipe",
PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0,
NMPWAIT_WAIT_FOREVER, NULL);
// Ожидание подключения клиента к каналу
ConnectNamedPipe (hNamedPipe, NULL);
// Запись данных в канал
WriteFile (hNamedPipe, lpSendData, dwSize, &dwWritten,
NULL);
// Отключение соединения с клиентом
DisconnectNamedPipe(hNamedPipe);
// Закрытие дескриптора канала
CloseHandle(hNamedPipe);

Приложение – клиент канала должно содержать следующий
код:

// Адрес блока получаемых данных
PVOID lpReceiveData;
// Размер блока данных и кол-во прочит. байтов
DWORD dwSize, dwRead;
…// Выделение памяти для блока данных
HANDLE hNamedPipe; // Дескриптор канала
// Ожидание освобождения канала
WaitNamedPipe("\\\\.\\pipe\\MyPipe",
NMPWAIT_WAIT_FOREVER);
// Подключение клиента к каналу
hNamedPipe = CreateFile("\\\\.\\pipe\\MyPipe",
GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
// Чтение данных из канала
ReadFile(hNamedPipe, lpReceiveData, dwSize, &dwRead,
NULL);
// Закрытие дескриптора канала
CloseHandle(hNamedPipe);

Примечание. Для организации передачи данных от клиента
к серверу необходимо: - при создании канала сервером с
помощью функции CreateNamedPipe() параметру
dwOpenMode задать значение PIPE_ACCESS_INBOUND; -
при открытии канала клиентом с помощью функции
CreateFile() параметрe dwDesiredAccess задать значение
GENERIC_WRITE.
Двухсторонняя передача данных между процессами с
использованием именованного канала
Для организации дуплексной передачи данных между
сервером и клиентом необходимо: - при создании канала
сервером с помощью функции CreateNamedPipe()
параметру dwOpenMode задать значение
PIPE_ACCESS_DUPLEX; - при открытии канала клиентом с
помощью функции CreateFile() параметру dwDesiredAccess
задать значение GENERIC_ READ | GENERIC_ WRITE.
Приложение – сервер канала должно содержать
следующий код:

// Адрес блока данных для запроса и ответа
PVOID lpRequest, lpResponse;
DWORD dwSize1, dwSize2; // Размеры блоков данных
// Кол-во прочитанных и записанных байтов
DWORD dwRead, dwWritten;
… // Выделение памяти для блоков данных
HANDLE hNamedPipe; // Дескриптор канала
// Создание именованного канала
hNamedPipe = CreateNamedPipe("\\\\.\\pipe\\MyPipe",
PIPE_ACCESS_DUPLEX, 0, 1, 0, 0,
NMPWAIT_WAIT_FOREVER, NULL);
// Ожидание подключения клиента к каналу
ConnectNamedPipe (hNamedPipe, NULL);
// Чтение в цикле запросов от клиента
while (ReadFile(hNamedPipe, lpRequest, dwSize1, &dwRead,
NULL))
{
… // Обработка очередного запроса
// Запись ответа в канал
WriteFile (hNamedPipe, lpResponse, dwSize2, &dwWritten,
NULL);
}
// Отключение соединения с клиентом
DisconnectNamedPipe(hNamedPipe);
// Закрытие дескриптора канала
CloseHandle(hNamedPipe);

Приложение – клиент канала должно содержать следующий
код:

// Адрес блока данных для запроса и ответа
PVOID lpRequest, lpResponse;
DWORD dwSize1, dwSize2; // Размеры блоков данных
// Кол-во прочитанных и записанных байтов
DWORD dwRead, dwWritten;
INT nReqCount; // Количество запросов к серверу
… // Выделение памяти для блоков данных
HANDLE hNamedPipe; // Дескриптор канала
// Ожидание освобождения канала
WaitNamedPipe("\\\\.\\pipe\\MyPipe",
NMPWAIT_WAIT_FOREVER);
// Подключение клиента к каналу
hNamedPipe = CreateFile("\\\\.\\pipe\\MyPipe", GENERIC_
READ | GENERIC_ WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
// Обмен с каналом, пока есть запросы
for (int i=0; i< nReqCount; i++)
{
… // Формирование очередного запроса
// Запись запроса в канал
WriteFile (hNamedPipe, lpRequest, dwSize1, &dwWritten,
NULL);
// Чтение ответа из канала
ReadFile(hNamedPipe, lpResponse, dwSize2, &dwRead,
NULL);
}
// Закрытие дескриптора канала
CloseHandle(hNamedPipe);

Таким образом, приведенные фрагменты исходного кода
показывают, как производится дуплексная передача
запросов и ответов между клиентом и сервером
именованного канала. Если сервер и клиент расположены
на разных компьютерах в сети, то в коде клиента при
вызове функции CreateFile() в имени канала необходимо
указывать сетевое имя компьютера сервера.
Дополнительные материалы
Использование почтовых ячеек для передачи данных
между процессами

Однонаправленная передача данных между процессами с


использованием почтовой ячейки
Рассмотрим использование описанных выше средств Win32
API для организации передачи данных от клиента к серверу
на одном компьютере.
Приложение – сервер почтовой ячейки должно содержать
следующий код:

// Адрес блока получаемых данных
PVOID lpReceiveData;
// Размер блока данных и кол-во прочит. байтов
DWORD dwSize, dwRead;
…// Выделение памяти для блока данных
HANDLE hMailslot; // Дескриптор почтовой ячейки
// Создание почтовой ячейки
hMailslot = CreateMailslot("\\\\.\\mailslot\\MyMailslot", 0,
MAILSLOT_WAIT_FOREVER, NULL);
// Чтение данных из почтовой ячейки
ReadFile(hMailslot, lpReceiveData, dwSize, &dwRead, NULL);
… // Обработка полученных данных
// Закрытие дескриптора почтовой ячейки
CloseHandle(hMailslot);

Приложение – клиент почтовой ячейки должно содержать
следующий код:

// Адрес блока передаваемых данных
PVOID lpSendData;
// Размер блока данных и кол-во запис. байтов
DWORD dwSize, dwWritten;
…// Выделение памяти и заполнение блока данными
HANDLE hMailslot; // Дескриптор почтовой ячейки
// Открытие клиентом почтовой ячейки
hMailslot = CreateFile("\\\\.\\mailslot\\MyMailslot", GENERIC_
WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
// Запись данных в канал
WriteFile(hMailslot, lpSendData, dwSize, &dwWritten, NULL);
// Закрытие дескриптора почтовой ячейки
CloseHandle(hMailslot);

Вам также может понравиться