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

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

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

#include <windows.h>

#include <iostream.h>

int main()

{

char c; // служебный символ

HANDLE hNamedPipe;

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

hNamedPipe=CreateNamedPipe(

"\\\\.\\pipe\\demo_pipe", // имя канала

PIPE_ACCESS_INBOUND, // читаем из канала

PIPE_TYPE_MESSAGE | PIPE_WAIT, // синхронная передача сообщений

1, // максимальное количество экземпляров канала

0, // размер выходного буфера по умолчанию

0, // размер входного буфера по умолчанию

INFINITE, // клиент ждет связь бесконечно долго

(LPSECURITY_ATTRIBUTES)NULL // защита по умолчанию

);

// проверяем на успешное создание

if (hNamedPipe==INVALID_HANDLE_VALUE)

{

cerr << "Creation of the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish server: ";

cin >> c;

return 0;

}

// ждем пока клиент свяжется с каналом

cout << "The server is waiting for connection with a client." << endl;

if(!ConnectNamedPipe(

hNamedPipe, // дескриптор канала

(LPOVERLAPPED)NULL // связь синхронная

))

{

cerr << "The connection failed." << endl

<< "The last error code: " << GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

// читаем данные из канала

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

{

int nData;

DWORD dwBytesRead;

if (!ReadFile(

hNamedPipe, // дескриптор канала

&nData, // адрес буфера для ввода данных

sizeof(nData), // количество читаемых байтов

&dwBytesRead, // количество прочитанных байтов

(LPOVERLAPPED)NULL // передача данных синхронная

))

{

cerr << "Data reading from the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

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

cout << "The number " << nData << " was read by the server" << endl;

}

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

CloseHandle(hNamedPipe);

// завершаем процесс

cout << "The data are read by the server."<<endl;

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

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

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

#include <windows.h>

#include <iostream.h>

int main()

{

char c; // служебный символ

HANDLE hNamedPipe;

char pipeName[] = "\\\\.\\pipe\\demo_pipe";

// связываемся с именованным каналом

hNamedPipe = CreateFile(

pipeName, // имя канала

GENERIC_WRITE, // записываем в канал

FILE_SHARE_READ, // разрешаем только запись в канал

(LPSECURITY_ATTRIBUTES) NULL, // защита по умолчанию

OPEN_EXISTING, // открываем существующий канал

0, // атрибуты по умолчанию

(HANDLE)NULL // дополнительных атрибутов нет

);

// проверяем связь с каналом

if (hNamedPipe == INVALID_HANDLE_VALUE)

{

cerr << "Connection with the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish the client: ";

cin >> c;

return 0;

}

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

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

{

DWORD dwBytesWritten;

if (!WriteFile(

hNamedPipe, // дескриптор канала

&i, // данные

sizeof(i), // размер данных

&dwBytesWritten, // количество записанных байтов

(LPOVERLAPPED)NULL // синхронная запись

))

{

// ошибка записи

cerr << "Writing to the named pipe failed: " << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish the client: ";

cin >> c;

CloseHandle(hNamedPipe);

return 0;

}

// выводим число на консоль

cout << "The number " << i << " is written to the named pipe." << endl;

Sleep(1000);

}

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

CloseHandle(hNamedPipe);

// завершаем процесс

cout << "The data are written by the client." << endl

<< "Press any char to finish the client: ";

cin >> c;

return 0;

}

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

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

// Сервер принимает сообщение от клиента и посылает ему сообщение в ответ.

// Внимание: в этом случае для работы в локальной сети вход на клиентскую машину должен быть выполнен

// с тем же именем и паролем, что и на сервер.

#include <windows.h>

#include <iostream.h>

int main()

{

char c; // служебный символ

HANDLE hNamedPipe;

char lpszInMessage[80]; // для сообщения от клиента

DWORD dwBytesRead; // для количества прочитанных байтов

char lpszOutMessage[] = "The server has received a message."; // обратное сообщение

DWORD dwBytesWrite; // для количества записанных байтов

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

hNamedPipe = CreateNamedPipe(

"\\\\.\\pipe\\demo_pipe", // имя канала

PIPE_ACCESS_DUPLEX, // читаем из канала и пишем в канал

PIPE_TYPE_MESSAGE | PIPE_WAIT, // синхронная передача сообщений

1, // максимальное количество экземпляров канала

0, // размер выходного буфера по умолчанию

0, // размер входного буфера по умолчанию

INFINITE, // клиент ждет связь 500 мс

(LPSECURITY_ATTRIBUTES)NULL // защита по умолчанию

);

// проверяем на успешное создание

if (hNamedPipe == INVALID_HANDLE_VALUE)

{

cerr << "Creation of the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish server: ";

cin >> c;

return 0;

}

// ждем, пока клиент свяжется с каналом

cout << "The server is waiting for connection with a client." << endl;

if(!ConnectNamedPipe(

hNamedPipe, // дескриптор канала

(LPOVERLAPPED)NULL // связь синхронная

))

{

cerr << "The connection failed." << endl

<< "The last error code: "<<GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

// читаем сообщение от клиента

if (!ReadFile(

hNamedPipe, // дескриптор канала

lpszInMessage, // адрес буфера для ввода данных

sizeof(lpszInMessage), // число читаемых байтов

&dwBytesRead, // число прочитанных байтов

(LPOVERLAPPED)NULL // передача данных синхронная

))

{

cerr << "Data reading from the named pipe failed." << endl

<< "The last error code: "<< GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

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

cout << "The server has received the following message from a client: "

<< endl << "\t" << lpszInMessage << endl;

// отвечаем клиенту

if (!WriteFile(

hNamedPipe, // дескриптор канала

lpszOutMessage, // адрес буфера для вывода данных

sizeof(lpszOutMessage), // число записываемых байтов

&dwBytesWrite, // число записанных байтов

(LPOVERLAPPED)NULL // передача данных синхронная

))

{

cerr << "Data writing to the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

// выводим посланное клиенту сообщение на консоль

cout << "The server send the following message to a client: "

<< endl << "\t" << lpszOutMessage << endl;

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

CloseHandle(hNamedPipe);

// завершаем процесс

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

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

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

// Сервер принимает сообщение от клиента и посылает ему сообщение в ответ.

// В этом случае для работы в локальной сети вход на клиентскую машину может быть

// выполнен с любым именем и паролем.

#include <windows.h>

#include <iostream.h>

int main()

{

char c; // служебный символ

SECURITY_ATTRIBUTES sa; // атрибуты защиты

SECURITY_DESCRIPTOR sd; // дескриптор защиты

HANDLE hNamedPipe;

char lpszInMessage[80]; // для сообщения от клиента

DWORD dwBytesRead; // для числа прочитанных байтов

char lpszOutMessage[] = "The server has received a message."; // обратное сообщение

DWORD dwBytesWrite; // для числа записанных байтов

// инициализация атрибутов защиты

sa.nLength = sizeof(sa);

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

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

InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);

// устанавливаем атрибуты защиты, разрешая доступ всем пользователям

SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);

sa.lpSecurityDescriptor = &sd;

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

hNamedPipe = CreateNamedPipe(

"\\\\.\\pipe\\demo_pipe", // имя канала

PIPE_ACCESS_DUPLEX, // читаем из канала и пишем в канал

PIPE_TYPE_MESSAGE | PIPE_WAIT, // синхронная передача сообщений

1, // максимальное количество экземпляров канала

0, // размер выходного буфера по умолчанию

0, // размер входного буфера по умолчанию

INFINITE, // клиент ждет связь 500 мс

&sa // доступ для всех пользователей

);

// проверяем на успешное создание

if (hNamedPipe == INVALID_HANDLE_VALUE)

{

cerr << "Creation of the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish server: ";

cin >> c;

return 0;

}

// ждем, пока клиент свяжется с каналом

cout << "The server is waiting for connection with a client." << endl;

if(!ConnectNamedPipe(

hNamedPipe, // дескриптор канала

(LPOVERLAPPED)NULL // связь синхронная

))

{

cerr << "The connection failed." << endl

<< "The last error code: " << GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

// читаем сообщение от клиента

if (!ReadFile(

hNamedPipe, // дескриптор канала

lpszInMessage, // адрес буфера для ввода данных

sizeof(lpszInMessage), // число читаемых байтов

&dwBytesRead, // число прочитанных байтов

(LPOVERLAPPED)NULL // передача данных синхронная

))

{

cerr << "Data reading from the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

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

cout << "The server has receivrd the following message from a client: "

<< endl << "\t" << lpszInMessage << endl;

// отвечаем клиенту

if (!WriteFile(

hNamedPipe, // дескриптор канала

lpszOutMessage, // адрес буфера для вывода данных

sizeof(lpszOutMessage), // число записываемых байтов

&dwBytesWrite, // число записанных байтов

(LPOVERLAPPED)NULL // передача данных синхронная

))

{

cerr << "Data writing to the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

CloseHandle(hNamedPipe);

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

// выводим посланное клиенту сообщение на консоль

cout << "The server send the following message to a client: "

<< endl << "\t" << lpszOutMessage << endl;

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

CloseHandle(hNamedPipe);

// завершаем процесс

cout << "Press any char to finish the server: ";

cin >> c;

return 0;

}

Теперь приведем пример клиента именованного канала, который вводит сначала с консоли имя компьютера в локальной сети, на котором запущен сервер именованного канала. Затем связывается с этим именованным каналом. После этого клиент передает серверу одно сообщение и получает от него сообщение в ответ, которое выводит на консоль.

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

#include <windows.h>

#include <iostream.h>

int main()

{

char c; // служебный символ

HANDLE hNamedPipe;

char machineName[80];

char pipeName[80];

char lpszOutMessage[]="How do you do server?"; // сообщение серверу

DWORD dwBytesWritten; // для числа записанных байтов

char lpszInMessage[80]; // для сообщения от сервера

DWORD dwBytesRead; // для числа прочитанных байтов

// вводим имя машины в сети, на которой работает сервер

cout << "Enter a name of the server machine: ";

cin >> machineName;

// подставляем имя машины в имя канала

wsprintf(pipeName, "\\\\%s\\pipe\\demo_pipe",

machineName);

// связываемся с именованным каналом

hNamedPipe = CreateFile(

pipeName, // имя канала

GENERIC_READ | GENERIC_WRITE, // читаем и записываем в канал

FILE_SHARE_READ | FILE_SHARE_WRITE, // разрешаем чтение и запись в канал

(LPSECURITY_ATTRIBUTES) NULL, // защита по умолчанию

OPEN_EXISTING, // открываем существующий канал

FILE_ATTRIBUTE_NORMAL, // атрибуты по умолчанию

(HANDLE)NULL // дополнительных атрибутов нет

);

// проверяем связь с каналом

if (hNamedPipe==INVALID_HANDLE_VALUE)

{

cerr << "Connection with the named pipe failed." << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish the client: ";

cin >> c;

return 0;

}

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

if (!WriteFile(

hNamedPipe, // дескриптор канала

lpszOutMessage, // данные

sizeof(lpszOutMessage), // размер данных

&dwBytesWritten, // количество записанных байтов

(LPOVERLAPPED)NULL // синхронная запись

))

{

// ошибка записи

cerr << "Writing to the named pipe failed: " << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish the client: ";

cin >> c;

CloseHandle(hNamedPipe);

return 0;

}

// выводим посланное сообщение на консоль

cout << "The client has send the following message to a server: "

<< endl << "\t" << lpszOutMessage << endl;

// читаем из именованного канала

if (!ReadFile(

hNamedPipe, // дескриптор канала

lpszInMessage, // данные

sizeof(lpszInMessage), // размер данных

&dwBytesRead, // количество записанных байт

(LPOVERLAPPED)NULL // синхронная запись

))

{

// ошибка записи

cerr << "Reading to the named pipe failed: " << endl

<< "The last error code: " << GetLastError() << endl;

cout << "Press any char to finish the client: ";

cin >> c;

CloseHandle(hNamedPipe);

return 0;

}

// выводим полученное сообщение на консоль

cout << "The client has received the following message from a server: "

<< endl << "\t" << lpszInMessage << endl;

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

CloseHandle(hNamedPipe);

// завершаем процесс

cout << "Press any char to finish the client: ";

cin >> c;

return 0;

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: