ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ
ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ
ЛИПЕЦКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
КАФЕДРА АВТОМАТИЗИРОВАННЫХ СИСТЕМ УПРАВЛЕНИЯ
Лабораторная работа 3
по дисциплине
«Операционные системы»
на тему:
«Реализация клиент-серверного приложения»
|
Студент |
|
|
|
Филатов А.А. |
|
||||||||
|
|
|
подпись, дата |
|
фамилия, инициалы |
|
||||||||
|
Группа |
|
АС-09-1 |
|
|
|
|
|||||||
|
|
|
|
|
|
|
||||||||
|
Принял |
|
|
|
|
|
||||||||
|
|
|
|
|
Журавлева М.Г. |
|
||||||||
|
ученая степень, звание |
|
подпись, дата |
|
фамилия, инициалы |
|
Липецк 2011
1.Задание
Реализовать программу-сервер и группу программ-клиентов, взаимодействующих с сервером с помощью механизма разделяемой памяти. Каждая программа-клиент обращается к серверу для реализации запроса на выполнение одной из двух функций (см. таблицу 2 Приложения с вариантами заданий). Клиент обращается с запросом к серверу, заполняя поля структуры запросы в блоке разделяемой памяти; Сервер обрабатывает запрос, выдает результат, помещая его в поле результата структуры запроса в разделяемой памяти.
Если сервер занят выполнением запроса и очередь клиентов на обслуживание не заполнена, клиент ставится в конец очереди (очередь реализуется по принципу FIFO). Максимальное количество клиентов в очереди задано. Если очередь заполнена, клиент, пытающийся получить доступ на обработку запроса, выгружается из памяти.
2.Алгоритм
Алгоритм работы клиента будет следующим:
1) ждать мьютекса разделяемого буфера, чтобы начать транзакцию;
2) заполнить поля запроса в разделяемом буфере;
3) выставить сигнал «запрос готов»;
4) ждать сигнала «результат готов»;
5) считать результат из разделяемого буфера и скопировать его в локальную память;
6) освободить мьютекс разделяемого буфера, тем самым завершая транзакцию.
Алгоритм сервера:
1) ждать сигнала «запрос готов»;
2) прочитать и разобрать поля запроса в разделяемом буфере;
3) выполнить запрошенные действия;
4) записать результат в соответствующее поле разделяемого буфера;
5) выставить сигнал «результат готов»;
6) перейти к шагу 1.
3. Листинг
Сервер.
#include <windows.h>
#include <conio.h>
#include <stdio.h>
HANDLE sh_bl;
HANDLE access_mutex;
HANDLE rq_ready;
HANDLE res_ready;
HANDLE semaphore;
// основные операции
const int STR = 123;
const int MATR = 678;
const int CLOSE_SRV = 999;
const int MAX_CONNECTION=10;
// имя сервера (фактически, имя блока разделяемой памяти, через который передаются запросы)
const char* srv_name = "SRV_1";
// имя мьютекса доступа к разделяемой памяти
const char* access_mutex_name = "SRV_1_M1";
// имя объекта события "запрос готов"
const char* request_ready_event_name = "SRV_1_E1";
// имя объекта события "результат готов"
const char* result_ready_event_name = "SRV_1_E2";
// имя объекта семафор
const char* semaphore_name = "SRV_1_SEMAPHOR";
//максимально возможная размерность массива
const int max_razm_mass=10;
const int max_size_string=256;
// структура разделяемого блока
struct SharedBlock
{
// код операции (заполняется клиентом)
int OpCode;
// количество фактических параметров (заполняется клиентом);
unsigned int razm_mass;
//строка
char Str[max_size_string];
// элементы матрицы
int Matr[ max_razm_mass*max_razm_mass ];
// результат выполнения запроса (заполняется сервером)
int UMatr[ max_razm_mass*max_razm_mass ];
// результат работы над строкой
char UStr[max_size_string];
};
SharedBlock *p;
void create_shared_block()
{
// Создаем именованный объект разделяемого отображения в
// страничной памяти с доступом на чтение и запись:
sh_bl = CreateFileMapping
(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof( SharedBlock ),
srv_name
);
// При попытке создания объекта с ранее зарегистрированным именем
// (здесь - при запуске второго экземпляра сервера)
// CreateFileMapping возвращает актуальный дескриптор,
// но при этом устанавливается специальный признак,
// доступный через GetLastError:
DWORD r = GetLastError();
// уклоняемся от запуска более одного экземпляра сервера
// (указатель на разделяемый блок останется нулевым,
// что при вызове enter_loop не позволит войти в цикл обработки)
if( r == ERROR_ALREADY_EXISTS )
return;
// если объект отображения был успешно создан (ненулевой дескриптор) ...
if( sh_bl )
{
// ... выполняем фактическое отображение участка страничной памяти
// на собственное адресное пространство (получаем актуальный указатель)
p = (SharedBlock *) MapViewOfFile
(
sh_bl,
FILE_MAP_ALL_ACCESS,
0, 0, 0
);
}
}
void execute_procedure( SharedBlock *block )
{
if( block->OpCode == STR )
{
printf("Type of request: STR\n");
printf("Inputed string: %s\n",block->Str);
block->UStr[0]=block->Str[0];
for(int i=1, j=1;i<strlen(block->Str);i++)
{
if(block->Str[i]!=block->UStr[j-1])
{
block->UStr[j]=block->Str[i];
j++;
}
}
printf("Updated string: %s\n\n",block->UStr);
}
else if( block->OpCode == MATR )
{
printf("Type of request: MATR\n");
for(int i=0;i<block->razm_mass;i++)
{
for(int j=0;j<block->razm_mass;j++)
{
printf("%d\t",block->Matr[i*block->razm_mass+j]);
}
printf("\n");
}
}
}
int main()
{
printf("Server has started\n");
create_shared_block();
semaphore = CreateSemaphore(NULL,MAX_CONNECTION,MAX_CONNECTION,semaphore_name);
// только актуальный (ненулевой) указатель на разделяемый блок
// позволяет работать с процессами клиентов:
if( p )
{
// создание мьютекса для эксклюзивного доступа к разделяемой памяти
access_mutex = CreateMutex
(
NULL, // дескриптор не может наследоваться дочерними процессами
TRUE, // изначально мьютексом владеет наш процесс
access_mutex_name // имя объекта
);
// создание объекта события "запрос готов"
rq_ready = CreateEvent
(
NULL, // дескриптор не может наследоваться дочерними процессами
FALSE, // автоматический сброс сигнала (ручной сброс не предусмотрен)
FALSE, // начальное состояние - сигнал сброшен
request_ready_event_name // имя объекта
);
// создание объекта события "результат готов"
res_ready = CreateEvent
(
NULL, // дескриптор не может наследоваться дочерними процессами
FALSE, // автоматический сброс сигнала (ручной сброс не предусмотрен)
FALSE, // начальное состояние - сигнал сброшен
result_ready_event_name // имя объекта
);
// если все объекты были успешно созданы ...
if( access_mutex && rq_ready && res_ready )
{
// ... освобождаем мьютекс (давая возможность кому-либо из клиентов его захватить)
ReleaseMutex( access_mutex );
res = true;
}
// если объекты синхронизации были успешно созданы ...
if( res )
{
// ... запускаем "вечный" цикл
for(;;)
{
// ждем сигнала "запрос готов"
printf("Waiting for request\n");
WaitForSingleObject( rq_ready, INFINITE );
printf("Request ready\n");
// если просят закрыться ...
if( p->OpCode == CLOSE_SRV )
{
printf("Type of request: CLOSE_SRV");
// ... выставляем сигнал готовности результата,
// на всякий случай - вдруг кто-то ждет подтверждения закрытия?
SetEvent( res_ready );
// прерываем "вечный" цикл (очень хочется сделать goto)
break;
}
// иначе - поступил обычный запрос
else
{
execute_procedure( p );
// выставляем сигнал готовности результата
SetEvent( res_ready );
}
} // end for(;;)
} // end if
// закрытие объектов синхронизации, независимо от того,
// все ли они были успешно созданы
if( access_mutex )
{
CloseHandle( access_mutex );
}
if( rq_ready )
{
CloseHandle( rq_ready );
}
if( res_ready )
{
CloseHandle( res_ready );
}
}
getch();
return res;
}
Клиент.
#include <conio.h>
#include <stdio.h>
#include <windows.h>
const DWORD timeout = 1000;
HANDLE sh_bl;
HANDLE semaphore;
HANDLE access_mutex;
HANDLE rq_ready;
HANDLE res_ready;
// основные операции
const int STR = 123;
const int MATR = 678;
const int CLOSE_SRV = 999;
const int MAX_CONNECTION=10;
// имя сервера (фактически, имя блока разделяемой памяти, через который передаются запросы)
const char* srv_name = "SRV_1";
// имя мьютекса доступа к разделяемой памяти
const char* access_mutex_name = "SRV_1_M1";
// имя объекта события "запрос готов"
const char* request_ready_event_name = "SRV_1_E1";
// имя объекта события "результат готов"
const char* result_ready_event_name = "SRV_1_E2";
// имя объекта семафор
const char* semaphore_name = "SRV_1_SEMAPHOR";
//максимально возможная размерность массива
const int max_razm_mass=10;
const int max_size_string=256;
// структура разделяемого блока
struct SharedBlock
{
// код операции (заполняется клиентом)
int OpCode;
// количество фактических параметров (заполняется клиентом);
unsigned int razm_mass;
//строка
char Str[max_size_string];
// элементыы матрицы
int Matr[ max_razm_mass*max_razm_mass ];
// результат выполнения запроса (заполняется сервером)
int UMatr[ max_razm_mass*max_razm_mass ];
// результат работы над строкой
char UStr[max_size_string];
};
SharedBlock *p;
bool ServerExists()
{
return ( p && access_mutex && rq_ready && res_ready );
}
void open_shared_block()
{
sh_bl = OpenFileMapping
(
FILE_MAP_ALL_ACCESS,
FALSE,
srv_name
);
if( sh_bl )
{
p = (SharedBlock *)MapViewOfFile
(
sh_bl,
FILE_MAP_ALL_ACCESS,
0, 0, 0
);
}
}
void open_sync_objects()
{
access_mutex = OpenMutex
(
MUTEX_ALL_ACCESS,
FALSE,
access_mutex_name
);
rq_ready = OpenEvent
(
EVENT_ALL_ACCESS,
FALSE,
request_ready_event_name
);
res_ready = OpenEvent
(
EVENT_ALL_ACCESS,
FALSE,
result_ready_event_name
);
}
void OnParamsPrepare( int code, SharedBlock *block )
{
char str[max_size_string];
block->OpCode = code;
if(code==STR)
{
printf("Input string:\n");
gets_s(str);
for(int i=0;i<strlen(str);i++)
{
block->Str[i]=str[i];
}
}
else if(code==MATR)
{
printf("Input size of matrix: ");
scanf("%d",&p->razm_mass);
for(int i=0;i<p->razm_mass;i++)
{
for(int j=0;j<p->razm_mass;j++)
{
printf("Input Matr[%d][%d]: ",i,j);
scanf("%d",&p->Matr[i*p->razm_mass+j]);
}
}
}
}
void clear_shared_block()
{
for(int i=0;i<max_razm_mass;i++)
{
p->Matr[i]=NULL;
p->UMatr[i]=NULL;
}
for(int i=0;i<max_size_string;i++)
{
p->Str[i]=p->UStr[i]='\0';
}
p->OpCode=0;
p->razm_mass=0;
}
bool call_procedure( int code )
{
bool r = false;
if( ServerExists() )
{
DWORD wait = WaitForSingleObject(semaphore,1000);
if(wait == WAIT_TIMEOUT)
{
printf("Wait timeout!\n");
return false;
}
else
printf("Waiting for server...\n");
DWORD res;
res = WaitForSingleObject( access_mutex, timeout );
if( res == WAIT_OBJECT_0 )
{
OnParamsPrepare( code, p );
SetEvent( rq_ready );
res = WaitForSingleObject( res_ready, timeout );
if( res == WAIT_OBJECT_0 )
{
r = true;
if(code==STR)
printf("Result: %s\n\n",p->UStr);
clear_shared_block();
}
ReleaseSemaphore(semaphore,1,NULL);
ReleaseMutex( access_mutex );
}
}
return r;
}
void main()
{
int code;
open_shared_block();
open_sync_objects();
semaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,semaphore_name);
if( ServerExists() )
{
printf("Server has found.\n");
do
{
printf("Choose type of operation:\n1.Massive\n2.String\n");
do
{
code=_getch();
printf("%c\n",code);
if(code=='1')
call_procedure(MATR);
else if(code=='2')
call_procedure(STR);
}while(code!='1' && code!='2' && code!='0');
}while(code!='0');
}
else
{
printf("Server not found.\n");
}
_getch();
}