- •Кафедра кит контрольная работа по дисциплине "Системное программирование"
- •Краматорск 2011 Задание №1
- •Задание №2
- •Задание №3
- •Решение
- •Задание №4 Обмен данными между приложениями с использованием технологии динамического обмена данными с помощью сокетов
- •Решение
- •Задание № 5 Обмен данными между приложениями с использованием технологии динамического обмена данными с помощью именованных каналов
- •Задание №6 Использование технологии сом при разработке приложений в Delphi. Создание и использование внутреннего сервера
Задание № 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. Хотя протокол "именованные каналы" работает эффективно, он обычно не используется в больших сетях, потому что он не поддерживает маршрутизацию и шлюзы.