Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Примеры работы с анонимными каналами




Вначале рассмотрим простой пример, в котором процесс-сервер выполняет следующие действия:

− создание анонимного канала;

− создание дочернего процесса;

− передача созданному дочернему процессу одного из дескрипторов созданного анонимного канала, используя для этого командную строку.

В этом случае дочерний процесс будет клиентом анонимного канала. Для определенности передадим клиенту дескриптор для записи в анонимный канал и оставим серверу дескриптор для чтения. Сначала приведем программу процесса-клиента анонимного канала.

Листинг 1. Пример процесса клиента анонимного канала.

// Клиент пишет в анонимный канал.

// Дескриптор анонимного канала передается клиенту через командную строку.

#include <windows.h>

#include <conio.h>

int main(int argc, char *argv[])

{

HANDLE hWritePipe;

// преобразуем символьное представление дескриптора в число

hWritePipe = (HANDLE)atoi(argv[1]);

// ждем команды о начале записи в анонимный канал

_cputs("Press any key to start communication.\n");

_getch();

// пишем в анонимный канал

for (int i = 0; i < 10; i++)

{

DWORD dwBytesWritten;

if (!WriteFile(

hWritePipe,

&i,

sizeof(i),

&dwBytesWritten,

NULL))

{

_cputs("Write to file failed.\n");

_cputs("Press any key to finish.\n");

_getch();

return GetLastError();

}

_cprintf("The number %d is written to the pipe.\n", i);

Sleep(500); }

// закрываем дескриптор канала

CloseHandle(hWritePipe);

_cputs("The process finished writing to the pipe.\n");

_cputs("Press any key to exit.\n");

_getch();

return 0;

}

 

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

 

Листинг 2. Пример процесса сервера анонимного канала.

// Сервер читает из анонимного канала. // Дескриптор анонимного канала передается // клинету через командную строку.

#include <windows.h> #include <conio.h>

int main() {

char lpszComLine[80]; // для командной строки

STARTUPINFO si;

PROCESS_INFORMATION pi;

HANDLE hWritePipe, hReadPipe, hInheritWritePipe;

// создаем анонимный канал if(!CreatePipe(

&hReadPipe, // дескриптор для чтения
&hWritePipe, // дескриптор для записи
NULL, // атрибуты защиты по умолчанию,

// в этом случае дескрипторы
// hReadPipe и hWritePipe ненаследуемые
0)) // размер буфера по умолчанию

{

_cputs("Create pipe failed.\n");

_cputs("Press any key to finish.\n");

_getch();

return GetLastError();

}

// делаем наследуемый дубликат дескриптора hWritePipe if(!DuplicateHandle(

GetCurrentProcess(), // дескриптор текущего процесса
hWritePipe, // исходный дескриптор канала

GetCurrentProcess(), // дескриптор текущего процесса
&hInheritWritePipe, // новый дескриптор канала
0, // этот параметр игнорируется

TRUE, // новый декскриптор наследуемый

DUPLICATE_SAME_ACCESS))// доступ не изменяем

{

_cputs("Duplicate handle failed.\n");

_cputs("Press any key to finish.\n");

_getch();

return GetLastError();

}

// закрываем ненужный дескриптор CloseHandle(hWritePipe);

// устанавливаем атрибуты нового процесса ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO);

// формируем командную строку wsprintf(lpszComLine, "C:\\Client.exe %d", (int)hInheritWritePipe);

// запускаем новый консольный процесс if (!CreateProcess(

NULL, // имя процесса

lpszComLine, // командная строка

NULL, // атрибуты защиты процесса по умолчанию

NULL, // атрибуты защиты первичного потока по умолчанию

TRUE, // наследуемые дескрипторы текущего процесса

// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL, // используем среду окружения процесса предка

NULL, // текущий диск и каталог, как и в процессе предке

&si, // вид главного окна - по умолчанию

&pi // здесь будут дескрипторы и идентификаторы

// нового процесса и его первичного потока)) {

_cputs("Create process failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); }

// закрываем дескрипторы нового процесса CloseHandle(pi.hProcess); CloseHandle(pi.hThread);

// закрываем ненужный дескриптор канала CloseHandle(hInheritWritePipe);

// читаем из анонимного канала for (int i = 0; i < 10; i++) {

int nData;

DWORD dwBytesRead;

if (!ReadFile(

hReadPipe, &nData, sizeof(nData), &dwBytesRead, NULL)) {

_cputs("Read from the pipe failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); } _cprintf("The number %d is read from the pipe.\n", nData); }

// закрываем дескриптор канала CloseHandle(hReadPipe);

_cputs("The process finished reading from the pipe.\n");

_cputs("Press any key to exit.\n");

_getch();

return 0; }

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

 

Листинг 3. Пример процесса клиента анонимного канала.

// Клиент сначала пишет в анонимный канал, а потом читает из него.

// Дескриптор анонимного канала передается клиенту через командную строку.

#include <windows.h> #include <conio.h>

int main(int argc, char *argv[]) {

HANDLE hWritePipe, hReadPipe;

HANDLE hEnableRead; // для синхронизации обмена данными

char lpszEnableRead[] = "EnableRead";

// открываем событие, разрешающее чтение hEnableRead = OpenEvent(EVENT_ALL_ACCESS, FALSE, lpszEnableRead);

// преобразуем символьное представление дескрипторов в число hWritePipe = (HANDLE)atoi(argv[1]); hReadPipe = (HANDLE)atoi(argv[2]);

// ждем команды о начале записи в анонимный канал

_cputs("Press any key to start communication.\n"); _getch();

// пишем в анонимный канал for (int i = 0; i < 10; i++) {

DWORD dwBytesWritten; if (!WriteFile(

hWritePipe, &i,

sizeof(i),

&dwBytesWritten, NULL)) {

_cputs("Write to file failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); } _cprintf("The number %d is written to the pipe.\n", i); } _cputs("The process finished writing to the pipe.\n");

// ждем разрешения на чтение WaitForSingleObject(hEnableRead, INFINITE); // читаем ответ из анонимного канала for (int j = 0; j < 10; j++) {

int nData;

DWORD dwBytesRead;

if (!ReadFile(

hReadPipe, &nData, sizeof(nData), &dwBytesRead, NULL)) {

_cputs("Read from the pipe failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); } _cprintf("The number %d is read from the pipe.\n", nData); }

_cputs("The process finished reading from the pipe.\n"); _cputs("Press any key to exit.\n"); _getch();

// закрываем дескрипторы канала CloseHandle(hWritePipe); CloseHandle(hReadPipe); CloseHandle(hEnableRead);

return 0; }

 

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

 

Листинг 4. Пример процесса сервера анонимного канала.

// Сервер сначала читает из анонимного канала, а затем пишет в него.

// Дескриптор анонимного канала передается клиенту через командную строку.

#include <windows.h> #include <conio.h>

int main() {

char lpszComLine[80]; // для командной строки

HANDLE hEnableRead; // для синхронизации обмена данными

char lpszEnableRead[] = "EnableRead";

STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE hWritePipe, hReadPipe; SECURITY_ATTRIBUTES sa;

// создаем событие для синхронизации обмена данными hEnableRead = CreateEvent(NULL, FALSE, FALSE, lpszEnableRead);

// устанавливает атрибуты защиты канала
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL; // защита по умолчанию

sa.bInheritHandle = TRUE; // дескрипторы наследуемые

// создаем анонимный канал if(!CreatePipe(

&hReadPipe, // дескриптор для чтения
&hWritePipe, // дескриптор для записи
&sa, // атрибуты защиты по умолчанию,

// дескрипторы наследуемые
0)) // размер буфера по умолчанию

{

_cputs("Create pipe failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); }

// устанавливаем атрибуты нового процесса ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO);

// формируем командеую строку wsprintf(lpszComLine, "C:\\Client.exe %d %d",

(int)hWritePipe, (int)hReadPipe); // запускаем новый консольный процесс if (!CreateProcess(

NULL, // имя процесса

lpszComLine, // командная строка

NULL, // атрибуты защиты процесса по умолчанию

NULL, // атрибуты защиты первичного потока по умолчанию

TRUE, // наследуемые дескрипторы текущего процесса

// наследуются новым процессом
CREATE_NEW_CONSOLE, // новая консоль
NULL, // используем среду окружения процесса предка

NULL, // текущий диск и каталог, как и в процессе предке

&si, // вид главного окна - по умолчанию

&pi // здесь будут дескрипторы и идентификаторы

// нового процесса и его первичного потока)) {

_cputs("Create process failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); }

// закрываем дескрипторы нового процесса CloseHandle(pi.hProcess); CloseHandle(pi.hThread);

// читаем из анонимного канала for (int i = 0; i < 10; i++) {

int nData;

DWORD dwBytesRead;

if (!ReadFile(

hReadPipe, &nData, sizeof(nData), &dwBytesRead, NULL)) {

_cputs("Read from the pipe failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); } _cprintf("The number %d is read from the pipe.\n", nData); } _cputs("The process finished reading from the pipe.\n");

// даем сигнал на разрешение чтения клиентом SetEvent(hEnableRead);

// пишем ответ в анонимный канал for (int j = 10; j < 20; j++) {

DWORD dwBytesWritten; if (!WriteFile(

hWritePipe, &j,

sizeof(j),

&dwBytesWritten, NULL)) {

_cputs("Write to file failed.\n"); _cputs("Press any key to finish.\n"); _getch();

return GetLastError(); } _cprintf("The number %d is written to the pipe.\n", j); }

// закрываем дескрипторы канала CloseHandle(hReadPipe); CloseHandle(hWritePipe); CloseHandle(hEnableRead);

_cputs("The process finished writing to the pipe.\n");

_cputs("Press any key to exit.\n");

_getch();

return 0; }

 

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

То есть для организации передачи данных необходимо разработать протокол передачи данных или использовать объекты синхронизации, которые исключают одновременный неконтролируемый доступ параллельных потоков к анонимному каналу. В приведенном примере событие hEnableRead сигнализирует клиенту, что сервер закончил чтение данных и теперь данные из канала может читать клиент. При отсутствии такой синхронизации возможно одновременное чтение данных сервером и клиентом, так как они работают параллельно, что вызовет неправильную работу программы и её зависание.





Поделиться с друзьями:


Дата добавления: 2016-11-24; Мы поможем в написании ваших работ!; просмотров: 1005 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Так просто быть добрым - нужно только представить себя на месте другого человека прежде, чем начать его судить. © Марлен Дитрих
==> читать все изречения...

2510 - | 2261 -


© 2015-2025 lektsii.org - Контакты - Последнее добавление

Ген: 0.01 с.