Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
сис прог печать.doc
Скачиваний:
33
Добавлен:
11.12.2018
Размер:
329.22 Кб
Скачать

Задание № 5 Обмен данными между приложениями с использованием технологии динамического обмена данными с помощью именованных каналов

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

Индивидуальное задание: Разработать серверное приложение, в котором осуществляется вызов изученных в соответствии с индивидуальным заданием к первой лабораторной работе функций, обработка и представление в понятном для пользователя виде возвращаемых ними результатов или достигаемых с их помощью эффектов (изменений режимов работы объектов операционной системы или пользовательского интерфейса).Разработать клиентское приложение, в котором будет осуществляться прием и отображение данных, получаемых по запросу от сервера. Организовать обмен данными, возвращаемыми Вашими функциями Windows API, между серверным и клиентским приложениями с использованием технологии сокетов.

Решение

1) Каналы рассматривались Microsoft как протокол для организации клиент-серверных приложений. Поэтому их сер­верная часть реализована только в среде Windows NT и выше и не поддерживается в Windows 95/98; клиенты могут быть созданы во всех этих ОС. Каналы - один из основных протоко­лов работы такого продукта, как Microsoft SQL Server.

2) В данном приложении необходимо организовать взаимодействие между клиентом и сервером посредством именованных каналов. Для определения имени канала используется соглашение UNC (Universal Naming Convention). Выглядеть оно должно так: \\<servername>\pipe\<pipename>, где servername — сетевое имя компьютера — сервера, pipename — имя кана­ла. В данной программе используется pipename = myserver и servername = . (локальное приложение).

3) Для открытия канала используем функцию CreateNamedPipe( lpszPipename,PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT,PIPE_UNLIMITED_INSTANCES,sizeof(Info),sizeof(Info),0,NULL)

Канал открыт дуплексный, неограниченное количество копий канала и отрытого в режиме обмена сообщениями. Для открытия канала со стороны клиента используется функция открытие файла CreateFile( pipeName, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL). С параметрами разрешения чтения и записи, с параметрами доступа по умолчанию.

Для чтения и записи используется стандартные функции WriteFile() и ReadFile(). Данные функции используются как сервером так и клиентом. Для опроса канала на наличия данных используется функция ConnectNamedPipe().

4) Сервер реализован в виде консольного приложения, которое создает поток для клиента, выполняет запрос и закрывает поток. Отображая информация в консоли программы.

Код сервера:

typedef struct tagInfo{

char s[80];

DWORD dwData;

DWORD attrib;

FILETIME time;

}Info;

Info in,out;

DWORD WINAPI InstanceThread(LPVOID);

VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

int _tmain(VOID)

{

BOOL fConnected = FALSE;

DWORD dwThreadId = 0;

HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;

LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\myserver");

for (;;)

{

_tprintf( TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);

hPipe = CreateNamedPipe(

lpszPipename,

PIPE_ACCESS_DUPLEX,

PIPE_TYPE_MESSAGE |

PIPE_READMODE_MESSAGE |

PIPE_WAIT,

PIPE_UNLIMITED_INSTANCES,

sizeof(Info),

sizeof(Info),

0,

NULL);

if (hPipe == INVALID_HANDLE_VALUE)

{

_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());

return -1;

}

fConnected = ConnectNamedPipe(hPipe, NULL) ?

TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

if (fConnected)

{

printf("Client connected, creating a processing thread.\n");

hThread = CreateThread(

NULL,

0,

InstanceThread,

(LPVOID) hPipe,

0,

&dwThreadId);

if (hThread == NULL)

{

_tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());

return -1;

}

else CloseHandle(hThread);

}

else

CloseHandle(hPipe);

}

return 0;

}

DWORD WINAPI InstanceThread(LPVOID lpvParam)

{

SYSTEMTIME Stime;

GetLocalTime(&Stime);

DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;

BOOL fSuccess = FALSE;

HANDLE hPipe = NULL;

printf("InstanceThread created, receiving and processing messages.\n");

hPipe = (HANDLE) lpvParam;

while (1)

{

fSuccess = ReadFile(

hPipe,

(PVOID)&in,

sizeof(Info),

&cbBytesRead,

NULL);

if(in.dwData == 5){

GetCurrentDirectory(80,out.s);

out.dwData = 10;

printf(out.s ,"\n");

}

if(in.dwData == 20){

SystemTimeToFileTime(&Stime,&out.time);

out.dwData = 25;

out.attrib = 100;

}

if (!fSuccess || cbBytesRead == 0)

{

if (GetLastError() == ERROR_BROKEN_PIPE)

{

_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());

}

else

{

_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());

}

break;

}

fSuccess = WriteFile(

hPipe,

(PVOID)&out,

sizeof(out),

&cbWritten,

NULL);

if (!fSuccess || cbReplyBytes != cbWritten)

{

_tprintf(TEXT("InstanceThread WriteFile failed, GLE=%d.\n"), GetLastError());

break;

}

}

FlushFileBuffers(hPipe);

DisconnectNamedPipe(hPipe);

CloseHandle(hPipe);

printf("InstanceThread exitting.\n");

return 1;

}

Код клиента:

typedef struct tagInfo{

char s[80];

DWORD dwData;

DWORD attrib;

FILETIME time;

}Info;

Info in,out;

char machineName[80];

char pipeName[80];

HANDLE hNamedPipe;

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

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

char pchMessage[80]; // для сообщения

int nMessageLength; // длина сообщения

__fastcall TForm10::TForm10(TComponent* Owner)

: TForm(Owner)

{

}

void __fastcall TForm10::Button1Click(TObject *Sender)

{

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

wsprintf(pipeName, "\\\\.\\pipe\\myserver", machineName);

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

hNamedPipe = CreateFile(

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

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

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

NULL, // безопасность по умолчанию

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

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

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

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

if (hNamedPipe==INVALID_HANDLE_VALUE)

{

ShowMessage("Error: "+ GetLastError());

}

strcpy(out.s,Edit1->Text.c_str());

out.dwData = 5;

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

if (!WriteFile(

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

(PVOID)&out, // данные

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

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

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

{

ShowMessage("Error: "+ GetLastError());

}

if (!ReadFile(

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

(PVOID)&in, // данные

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

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

NULL)) // синхронное чтение

{

ShowMessage("Error: "+ GetLastError());

}

if(in.dwData == 10){

Edit2->Text = in.s;

}

CloseHandle(hNamedPipe);

}

void __fastcall TForm10::Button2Click(TObject *Sender)

{

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

wsprintf(pipeName, "\\\\.\\pipe\\myserver", machineName);

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

hNamedPipe = CreateFile(

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

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

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

NULL, // безопасность по умолчанию

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

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

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

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

if (hNamedPipe==INVALID_HANDLE_VALUE)

{

ShowMessage("Error: "+ GetLastError());

}

out.dwData = 20;

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

if (!WriteFile(

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

(PVOID)&out, // данные

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

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

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

{

ShowMessage("Error: "+ GetLastError());

}

if (!ReadFile(

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

(PVOID)&in, // данные

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

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

NULL)) // синхронное чтение

{

ShowMessage("Error: "+ GetLastError());

}

if(in.dwData == 25){

Edit3->Text = in.time.dwHighDateTime;

Edit1->Text = in.time.dwLowDateTime;

}

CloseHandle(hNamedPipe);

Вывод: Именованные каналы – это клиентский протокол, применяемый по умолчанию, и он является протоколом, применяемым по умолчанию в операционных системах Windows NT 4 Server и Windows 2000. В операционных системах Microsoft Windows 95 и Microsoft Windows 98 именованные каналы применяться не могут. В этих системах на стороне сервера применяются протоколы TCP/IP, multiprotocol и shared memory. Хотя протокол "именованные каналы" работает эффективно, он обычно не используется в больших сетях, потому что он не поддерживает маршрутизацию и шлюзы.