Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа №3 Вариант 10.doc
Скачиваний:
16
Добавлен:
20.06.2014
Размер:
206.34 Кб
Скачать

2

ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ

ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ

ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

ЛИПЕЦКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

КАФЕДРА АВТОМАТИЗИРОВАННЫХ СИСТЕМ УПРАВЛЕНИЯ

Лабораторная работа 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();

}