Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
АОПИ. Старое / АОПИ. Глава 2. Конспекты (02_04_19).rtf
Скачиваний:
65
Добавлен:
10.09.2019
Размер:
363.46 Кб
Скачать

Обмен данными по анонимному каналу

Для обмена данными по анонимному каналу в операционных системах Windows используются те же функции, что для записи и чтения данных в файл.

Для записи данных в анонимный канал используется функция WriteFile.

BOOL WriteFile(

HANDLE hAnonPipe,

LPCVOID lpBuffer,

DWORD nNumberOfBytesToWrite,

LPDWORD lpNumberOfBytesWritten,

LPOVERLAPPED lpOverlapped

);

Параметры и описание:

(1) hAnonPipe — определяет дескриптор анонимного канала.

(2) lpBuffer — определяет буфер данных.

(3) nNumberOfBytesToWrite — определяет число байт для записи.

(4) lpNumberOfBytesWritten — определяет число записанных байт.

(5) lpOverlapped — предназначен для выполнения асинхронной операции вывода.

Возвращаемое значение.

При успешном завершении возвращает значение TRUE, а в случае неудачи – FALSE.

Вызов WriteFile не возвращается, пока он не записал указанное число байтов в канал или не произойдет ошибка.

Описание.

Функция WriteFile записывает в анонимный канал количество байт, заданных параметром nNumberOfBytesToWrite, из буфера данных, на который указывает параметр lpBuffer.

Дескриптор вывода этого анонимного канала должен быть задан первым параметром функции WriteFile.

Количество байт, записанных этой функцией в анонимный канал, возвращается в переменной, на которую указывает параметр lpNumberOfBytesWritten.

Параметр lpOverlapped предназначен для выполнения асинхронной операции вывода, так как анонимные каналы поддерживают только синхронную передачу данных, то в нашем случае этот параметр всегда будет равен NULL.

Для чтения данных из анонимного канала используется функция ReadFile.

BOOL ReadFile(

HANDLE hAnonPipe,

LPCVOID lpBuffer,

DWORD nNumberOfBytesToWrite,

LPDWORD lpNumberOfBytesWritten,

LPOVERLAPPED lpOverlapped

);

Параметры и описание:

(1) hAnonPipe — определяет дескриптор анонимного канала.

(2) lpBuffer — определяет буфер данных.

(3) nNumberOfBytesToWrite — определяет число байт для записи.

(4) lpNumberOfBytesWritten — определяет число записанных байт.

(5) lpOverlapped — предназначен для выполнения асинхронной операции вывода.

Возвращаемое значение.

При успешном завершении возвращает значение TRUE, а в случае неудачи – FALSE.

Вызов ReadFile возвращается, когда другой канал записал в канал. Вызов ReadFile также может возвращаться, если все дескрипторы записи в канал были закрыты или если произошла ошибка до завершения операции чтения.

Описание.

Функция ReadFile читает из анонимного канала количество байт, заданных параметром nNumberOfBytesToRead, в буфер данных, на который указывает параметр lpBuffer.

Дескриптор ввода этого анонимного канала должен быть задан первым параметром функции ReadFile.

Количество байт, прочитанных функцией WriteFile из анонимного канала, возвращается в переменной, на которую указывает параметр lpNumberOfBytesRead. Также как и в случае записи в анонимный канал параметр lpOverlapped должен быть равен NULL.

Итог

Дескриптор для записи в анонимный канал должен быть параметром функции WriteFile, а дескриптор для чтения из анонимного канала должен быть параметром функции ReadFile. В этом и состоит смысл передачи данных по анонимному каналу только в одном направлении. Однако это не означает, что один процесс может использовать анонимный канал только для записи или только для чтения. Один и тот же процесс может, как писать данные в анонимный канал, так и читать данные из него, должным образом используя дескрипторы этого анонимного канала.

После завершения обмена данными по анонимному каналу, потоки должны закрыть дескрипторы записи и чтения анонимного канала, используя функцию CloseHandle.

Схема обмена данными по анонимному каналу

Процесс-сервер.

1. Создает анонимный канал.

2. Создает дубликат дескриптора, устанавливая должное наследование с помощью DuplicateHandle.

3. Закрывает ненужный дублированный дескриптор.

4. Подготавливает входные параметры для функции CreateProcess.

5. Создает дочерний процесс с помощью функции CreateProcess, задавая bInheritHandle равным TRUE. fdwCreate (dwCreationFlags) устанавливается в CREATE_NEW_CONSOLE (0x00000010).

6. Закрывает дескрипторы нового процесса и потока.

7. Выполняет чтение из анонимного канала.

8. Закрывает дескриптор чтения из канала.

Процесс-клиент.

1. Записывает данные в анонимный канал.

2. Закрывает дескриптор чтения из канала.

Пример (C++).

Запускается только SERVER.EXE

CLIENT

#include <stdio.h>

int main () {

int x, y;

scanf("%d%d",&x,&y); /// Получаем два числа

printf("%d", x+y); /// Складываем два числа

return 0;

}

SERVER

#include <windows.h>

#include <stdio.h>

#include <string.h>

#include <iostream>

#define CLIENT_FILE "Client1.exe" /// EXE файл клиента

using namespace std;

int main() {

setlocale(LC_ALL, "Russian"); /// Русский язык

char buf[1024];

SECURITY_ATTRIBUTES sa;

PROCESS_INFORMATION pi;

HANDLE newstdread, newstdwrite; /// Дескрипторы

sa.nLength = sizeof(sa);

sa.lpSecurityDescriptor = NULL;

sa.bInheritHandle = true; /// Наследование

/// Создаем канал

if (!CreatePipe(&newstdread, &newstdwrite, &sa, 0)) {

cout << "Pipe не создан...\n";

getchar();

return 0;

}

else cout << "Pipe создан!\n";

STARTUPINFO si = {sizeof(si)};

ZeroMemory(&si, sizeof(STARTUPINFO)); /// Очистка

/// Далее настройка информации о процессе

si.cb = sizeof(STARTUPINFO);

si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

si.wShowWindow = SW_NORMAL;

si.hStdInput = newstdread; /// Перенаправляем поток ввода

si.hStdOutput = newstdwrite; /// Перенаправляем поток вывода

si.hStdError = si.hStdOutput; /// Перенаправляем поток ошибок

TCHAR czCommandLine[] = CLIENT_FILE; /// Наш клиент

/// Создаем процесс

if (!CreateProcess(NULL, czCommandLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {

cout << "Процесс не создан...\n";

getchar();

CloseHandle(newstdread);

CloseHandle(newstdwrite);

return 0;

}

else

cout << "Процесс создан!\n";

unsigned long with_file;

/// Доп. информация

cout << "STD INPUT HANDLE = " << newstdread << endl;

cout << "STD OUTPUT HANDLE = " << newstdwrite << endl;

strcpy(buf,"332 633\n"); /// Два числа отправляем в поток ввода клиента

WriteFile(newstdwrite, buf, strlen(buf), &with_file, NULL);

Sleep(100); /// Чуть-чуть спим

memset(buf, '\0', sizeof(buf));

ReadFile(newstdread, buf, 100, &with_file, NULL);

printf("Результат: %s\n",buf); /// Получаем результат от клиента

TerminateProcess(pi.hProcess,0); /// Закрываем процесс

CloseHandle(pi.hThread); /// Закрываем дескрипторы

CloseHandle(pi.hProcess); /// Закрываем дескрипторы

CloseHandle(newstdread); /// Закрываем дескрипторы

CloseHandle(newstdwrite); /// Закрываем дескрипторы

getchar(); /// Пауза перед выходом

return 0;

}