Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
mkr_EVM v ASUTP.doc
Скачиваний:
7
Добавлен:
10.02.2016
Размер:
373.25 Кб
Скачать

1.5. Выбор архитектуры

Если сравнивать разработку ПО с процессом постройки моста, то анализ требований будет аналогичен выбору мест, где мост будет начинаться и заканчиваться, а также определению рода нагрузок, которые он должен выдерживать. Далее, архитектор моста должен решить, каким будет мост: подвесным, консольным или какого-то другого типа, удовлетворяющего требованиям. Другими словами он должен определить архитектуру моста. Разработчик ПО сталкивается с похожим выбором.

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

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

За выбором архитектуры следует детальное проектирование, основной целью которого является как можно более полная подготовка проекта к его реализации. Другими словами, программисты должны иметь возможность реализовать детальный проект, сконцентрировавшись только на проблемах, связанных с созданием программного кода.

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

На рис. 3 представлен один из вариантов архитектуры ПО для данной курсовой работы.

Рис.3. Архитектура ПО модели АСУ ТМП

Данная архитектура удовлетворяет всем требованиям изложенным в разделе 1.4. В общем случае, если используется технология «Клиент-Сервер», сетевые интерфейсы являются различными модулями и архитектура ПО состоит из шести модулей. Если используются другие технологии, сетевые интерфейсы могут ОУ и регулятора могут быть реализованы в виде одного и того же модуля. В этом случае архитектура будет состоять из пяти модулей.

В данной курсовой работе студентам рекомендуется использовать технологию сетевого взаимодействия приложений основанную на использовании каналов (pipes). Основы использования данной технологии изложены в[2].

1.6. Детальное проектирование

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

В данной курсовой работе студенты должны разработать алгоритмы и модели для ПО АСУ ТМП используя объектно-ориентированный анализ.

Рекомендуется использовать при детальном проектировании следующую последовательность действий.

1) Разработать пользовательские интерфейсы. На данном этапе следует реализовать все требования предъявляемые к пользовательским интерфейсам и создать прототипы интерфейсных функций. Варианты интерфейсов для ОУ и регулятора представлены на рис. 4, 5.

Рис. 4. Вариант пользовательского интерфейса для ОУ

Рис. 5. Вариант пользовательского интерфейса для регулятора

2) Выделить подсистемы для анализа и синтезировать информационные модели. На основании анализа требований заказчика можно выделить для анализа две подсистемы: ОУ и регулятор. Далее следует разработать информационные модели для каждой подсистемы.

3) Синтезировать модели состояний для каждого объекта информационных моделей.

4) В случае наличия специфических действий в определенных состояниях, разработать алгоритмы этих действий. В данной работе к специфическим следует отнести алгоритмы расчета температуры пластинки и расчета управляющего воздействия.

5) Составить спецификацию классов. Пр этом в основе спецификации должны лежать информационные модели. В зависимости от характера и сложности решаемой задачи могут понадобиться дополнительные классы. Например, в данной курсовой работе можно ввести базовый классCBaseIntefaceдля интерфейсов сетевого взаимодействия, и, унаследовав свойства базового класса, реализовать собственно классы для сетевых интерфейсов ОУ и регулятора.

6) Составить для каждого класса спецификацию функций с указанием граничных условий для входных и выходных параметров.

7) Составить предварительный план тестирования. План тестирования должен содержать проверки подтверждающие правильную реализацию каждого требования к ПО содержащегося в спецификации требований.

8) Перейти к реализации ПО.

Теперь рассмотрим более подробно вопросы практического использования технологии сетевого взаимодействия на основе каналов. Хотя эти вопросы относятся скорее к реализации (см. п.1.7). Некоторые специфические моменты существенно влияют на общую концепцию, а именно на архитектуру, спецификацию классов и функций. Поэтому на этапе детального проектирования также следует продумать пути решения тех или иных задач и разработать соответствующее алгоритмическое обеспечение.

Предположим, что мы будем использовать технологию «Клиент-Сервер». Пусть модель ОУ будет выполнять функцию сервера, а модель регулятора — функцию клиента.

Создание сервера осуществляется вызовом функции CreateNamedPipe(). Далее при помощи функцииConnectNamedPipe()ожидается подключение клиента (см. листинг 4).

Листинг 4. Создание сервера и ожидание подключения клиента.

m_hPipeWrite = CreateNamedPipe( "\\\\.\\pipe\\write", // pipe name

PIPE_ACCESS_OUTBOUND, // read/write access

PIPE_WAIT, // blocking mode

PIPE_UNLIMITED_INSTANCES, // max. instances

256, // output buffer size

256, // input buffer size

5000, // client time-out

NULL); // no security attribute

if (m_hPipeWrite == INVALID_HANDLE_VALUE)

{

// обработка ошибки

}

fConnectedRead = ConnectNamedPipe(m_hPipeWrite, NULL) ?

TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

Специфика функции ConnectNamedPipe()заключается в том, что пока клиент не подключится, программа дальше выполняться не будет. Возникает эффект «зависания» программы.

Второй специфический момент связан с чтением данных из канала функцией ReadFile(). В параметрах функции указывается число считываемых байт. Здесь также наблюдается эффект «зависания» до тех пор, пока из канала не будет прочитано заявленное число байт.

Для решения проблемы зависания студентам рекомендуется использовать потоки. Еще лучше сделать классы сервера и клиента потоковыми. Анализ задачи показывает, что для реализации взаимодействия сервера и клиента необходимо четыре потока. Во-первых, целесообразно сами классы сервера и клиента сделать потоковыми. Во-вторых, в отдельных потоках должна быть реализована функция чтения данных из канала как для сервера, так и для клиента.

Целесообразно разработать базовый родительский класс позволяющий создавать объекты работающие в отдельных потоках. В листингах 5 и 6 приведен пример такого базового потокового класса CThread.

Листинг 5.h-файл базового потокового класса.

// Filename: threadclass.h

// Описание класса потока.

#ifndef __THREADCLASS_H

#define __THREADCLASS_H

#include "stdafx.h"

class CThread

{

// Атрибуты

private:

HANDLE hThread; // Дескриптор потока

DWORD IDThread; // Идентификатор потока

BOOL bNeedDestroy; // Признак уничтожения потока

// TRUE - поток уничтожается

// FALSE – поток не уничтожается

// Методы

public:

// Конструктор

// dwFlag – флаг создания потока (CREATE_SUSPENDED или нет)

// ВНИМАНИЕ! Если поток создается без флага CREATE_SUSPENDED,

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

// потока до завершения инициализации класса!

CThread(DWORD dwFlag);

// Деструктор

virtual ~CThread();

protected:

// Переопределяемая функция выполнения потока

virtual DWORD ThreadExecuter(void) = 0;

// Собственно поток. Вызывает ThreadExecuter

DWORD ThreadFunc(void);

// Функция потока

static DWORD WINAPI CommonThreadFunc(LPVOID lpCThreadObject);

// Функция завершения потока.

// Эту функцию необходимо вызывать из всех деструкторов

// порожденных классов до освобождения любых ресурсов

void EndThread(void);

// Установка приоритета потока

BOOL SetPriority(int Priority);

// Проверка на выполнение потока.

BOOL IsThreadWork(void);

// Проверка на остановку потока.

BOOL IsThreadResumed(void);

// Принудительное завершение выполнения потока.

BOOL Terminate(DWORD dwExitCode);

public:

// Функция запуска потока

DWORD Resume(void);

// Функция приостановки потока

DWORD Suspend(void);

};

#endif

Листинг 6. сpp-файл базового потокового класса.

// Filename: threadclass.cpp

#include "threadclass.h"

// Конструктор

CThread::CThread(DWORD dwFlag)

{

bNeedDestroy = FALSE;

// Создаем поток

hThread = CreateThread(NULL, 0, CommonThreadFunc, this, dwFlag, &IDThread);

}

// Деструктор

CThread::~CThread()

{

// Завершаем поток

EndThread();

}

// Собственно поток. Вызывает ThreadExecuter

DWORD CThread::ThreadFunc(void)

{

DWORD Ret;

while (!bNeedDestroy)

{

Ret = ThreadExecuter();

// Проверка на завершение

if ( Ret == WAIT_FAILED ) break;

}

return Ret;

}

// Функция потока

DWORD WINAPI CThread::CommonThreadFunc(LPVOID lpCThreadObject)

{

CThread* ThreadObject = static_cast<CThread*>(lpCThreadObject);

if ( !ThreadObject ) return 0xFFFFFFFF;

return ThreadObject->ThreadFunc();

}

// Функция завершения потока

void CThread::EndThread(void)

{

bNeedDestroy = TRUE;

// Переводим поток в спящее состояние и получаем его счетчик.

DWORD Ret = 0;

GetExitCodeThread(hThread, &Ret);

if ( Ret == STILL_ACTIVE )

{

// Поток выполняется. Ждем завершение его работы

WaitForSingleObject(hThread, INFINITE);

}

// В других случаях: поток не выполняется – можно просто

// удалять.

}

// Установка приоритета потока

BOOL CThread::SetPriority(int Priority)

{

return SetThreadPriority(hThread, Priority);

}

// Проверка на выполнение потока.

BOOL CThread::IsThreadWork(void)

{

DWORD Ret = 0;

GetExitCodeThread(hThread, &Ret);

if ( Ret == STILL_ACTIVE )

{

return TRUE;

}

return FALSE;

}

// Проверка на остановку потока.

BOOL CThread::IsThreadResumed(void)

{

// Переводим поток в спящее состояние и получаем его счетчик.

DWORD Ret = SuspendThread(hThread);

// Восстанавливаем его выполнение.

ResumeThread(hThread);

if ( Ret == 0 )

{

// Счетчик был нулевой – поток был в работоспособном

// состоянии.

return FALSE;

}

return TRUE;

}

// Принудительное завершение выполнения потока.

BOOL CThread::Terminate(DWORD dwExitCode)

{

DWORD dwCurThreadID = GetCurrentThreadId();

if ( dwCurThreadID != IDThread )

{

bool ret = TerminateThread(hThread, dwExitCode);

return ret;

}

return FALSE;

}

// Функция запуска потока

DWORD CThread::Resume()

{

DWORD dwCurThreadID = GetCurrentThreadId();

if ( dwCurThreadID != IDThread )

{

return ResumeThread(hThread);

}

return 0;

}

// Функция приостановки потока

DWORD CThread::Suspend()

{

DWORD dwCurThreadID = GetCurrentThreadId();

if ( dwCurThreadID != IDThread )

{

return SuspendThread(hThread);

}

return 0;

}

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

Самое простое и неправильное решение заключается в передаче в соответствующий класс указателей на элементы управления, предназначенные для вывода необходимой информации, и реализацию в классах сервера и клиента функций обмена с интерфейсом. Неправильность очевидна. Модуль сетевого взаимодействия (сервер/клиент) который мог бы применяться в других программах жестко привязан к определенному пользовательскому интерфейсу.

Более правильным подходом является использование интерфейсного класса который позволит брать необходимую информацию из сервера/клиента и выводить в соответствующие элементы пользовательского интерфейса. В этом случае при изменении интерфейса для сохранности работоспособности необходимо лишь слегка модифицировать интерфейсный класс. При этом сами классы сервера и клиента становятся универсальными и могут без переделки применяться в различных программах.

В листингах 7-9 приведен пример реализации такого интерфейсного класса CMsgOut.

Листинг 7. h-файл базового интерфейсного класса IMsgOut.

// Filename: IMsgOut.h

#ifndef __IMSG_OUT_H

#define __IMSG_OUT_H

class IMsgOut

{

public:

// Метод вывода на экран различных сообщений.

// pData - указатель на данные асоциированные с данным сообщением.

// unWaitTime - время ожидания реакции оператора на данное сообщение.

virtual void MsgOut( char* szMsgText, void* pData, unsigned dwWaitTime = 0 ) = 0;

};

#endif

Листинг 8. h-файл интерфейсного класса CMsgOut.

// Filename: MsgOut.h

#ifndef __MSG_OUT_H

#define __MSG_OUT_H

#include "IMsgOut.h"

#include "afxwin.h"

enum ServerStatus

{

ssWait,

ssSend,

ssRecive

};

class CMsgOut : public IMsgOut

{

protected:

CListBox* m_pOutputWindow; // Указатель на компонент в

// который выводятся сообщения.

// Статус состояния объекта (Сервера/клиента).

ServerStatus m_Status;

public:

bool bInit;

// Метод вывода на экран различных сообщений.

// Данные:

// szMsgText - указатель на текст сообщения.

// pData - указатель на данные ассоциированные с данным сообщением.

// unWaitTime - время ожидания реакции оператора на данное сообщение.

void MsgOut( char* szMsgText, void* pData = NULL, unsigned unWaitTime = 0 );

bool IsInit( void );

ServerStatus GetServerStatus(void);

void SetServerStatus( ServerStatus NewStatus );

public:

// Конструктор.

CMsgOut( CListBox* pOutputWindow );

// Деструктор.

~CMsgOut();

};

#endif

Листинг 9. cpp-файл интерфейсного класса.

// Filename: MsgOut.cpp

#include "MsgOut.h"

// Метод вывода на экран различных сообщений.

// Данные:

// szMsgText - указатель на текст сообщения.

// pData - указатель на данные ассоциированные с данным сообщением.

// unWaitTime - время ожидания реакции оператора на данное

// сообщение.

void CMsgOut::MsgOut( char* szMsgText, void* pData, unsigned unWaitTime )

{

if ( unWaitTime != 0 )

{

SetServerStatus( ssWait );

}

int nPosition = m_pOutputWindow->AddString( szMsgText );

// проверка!

if ( pData )

{

// Обработка данных

}

m_pOutputWindow->SetCurSel( nPosition );

}

bool CMsgOut::IsInit( void )

{

return bInit;

}

ServerStatus CMsgOut::GetServerStatus(void)

{

return m_Status;

}

void CMsgOut::SetServerStatus( ServerStatus NewStatus )

{

m_Status = NewStatus;

}

// Конструктор.

CMsgOut::CMsgOut( CListBox* pOutputWindow )

{

bInit = true;

m_pOutputWindow = pOutputWindow;

if ( !m_pOutputWindow ) bInit = false;

}

// Деструктор.

CMsgOut::~CMsgOut()

{

}

Теперь все готово для реализации собственно классов сервера и клиента. В листингах 10 и 11 приведен пример реализации класса CServer.

Листинг 10.h-файл класса CServer.

// Filename: Server.h

#ifndef __SERVER_H

#define __SERVER_H

#include "ThreadClass.h"

#include "IMsgOut.h"

enum IOperations

{

ISuccess = 0, // Нормальное завершение без ожидания действий

// оператора.

IStop, // Оператор останавливает выполнение распознавания.

IContinue,// Оператор подтверждает продолжение распознавания.

ITimeOut, // Завершено ожидание действий оператора.

IError // Возникла ошибка.

};

// Структура даннных используемых при неправильном завершении теста.

struct CThrowData

{

char* szMsgText; // Текст сообщения.

void* pData; // Посылаемые данные.

};

class CServer : public CThread

{

protected:

bool bInit;

HANDLE m_hStopEvent; // Дескриптор события

// принудительного завершения выполнения распознавания.

HANDLE m_hContinueEvent; // Дескриптор события

// продолжения выполнения распознавания.

BOOL m_bWaitOper; // Флаг ожидания сообщений

// от оператора. TRUE - идет ожидание сообщения, FALSE - нет.

CRITICAL_SECTION m_CritSection; // Критическая секция для

// синхронизации доступа к флагу ожидания сообщения от оператора.

IMsgOut* m_pIMsgOut; // Указатель на интерфейсный

// класс.

HANDLE m_hPipeRead;

HANDLE m_hPipeWrite;

protected:

// Переопределяемая функция выполнения потока.

// При останове потока возвращается WAIT_FAILED, иначе - поток

// продолжает свое выполнение.

virtual DWORD ThreadExecuter(void);

// Послать сообщение оператору.

// Параметры:

// szMsgText - посылаемое сообщение в виде текста.

// pData - указатель на данные асоциированные с данным

// сообщением(время прихода сообщения).

// unWaitTime - время ожидания подтверждения от оператора в

// миллисекундах.

// Если dwWaitTime равно нулю, то ожидание не выполняется. Если

// dwWaitTime равно INFINITE,

// то ожидание будет выполняться бесконечно долго.

// Возврат:

// ISuccess - нормальное завершение без ожидания действий

// оператора.

// IStop - оператор останавливает распознавания.

// IContinue - выполнялось ожидание действий оператора и

// оператор подтвердил выполнение действий.

// ITimeOut - не было подтверждения от оператора в течении

// заданного времени.

// IError - ошибка.

IOperations MsgToOperator( char* szMsgText, void* pData = NULL, unsigned unWaitTime = 0 );

void GenExeption(char* szMsgText, void* pData);

public:

// Виртуальный метод выполнения распознавания. Метод вызывается

// из ThreadExecuter.

// Не вызывать этот метод из других потоков!

bool Run();

// Метод запуска/возобновления распознавания.

bool StartResume(void);

// Метод временной остановки распознавания.

bool Pause(void);

// Метод принудительного завершения распознавания.

bool Stop(void);

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

bool IsDoing(void);

// Метод проверки статуса инициализации распознавания.

bool IsInit(void)

{

return bInit;

}

static DWORD WINAPI InstanceThread(LPVOID lpvParam);

void GetAnswerToRequest(LPTSTR chRequest, LPTSTR chReply, LPDWORD cbReplyBytes);

void SendRequest(char* pszRequest, int nReplyBytes);

public:

// Конструктор.

// pIMsgOut - указатель наинтерфейсный класс.

CServer( IMsgOut* m_pIMsgOut );

// Деструктор.

virtual ~CServer();

};

#endif

Листинг 11. cpp-файл класса CServer.

// Filename: Server.cpp

/*

Реализация методов класса CServer.

*/

#include "Server.h"

// Переопределяемая функция выполнения потока.

// При останове потока возвращается WAIT_FAILED, иначе - поток продолжает свое выполнение.

DWORD CServer::ThreadExecuter(void)

{

if ( !bInit ) return WAIT_FAILED;

// Просто вызываем метод Test. По его завершению возвращаем WAIT_FAILED.

Run();

return WAIT_FAILED;

}

// Послать сообщение оператору.

// Параметры:

// szMsgText - посылаемое сообщение в виде текста.

// pData - указатель на данные асоциированные с данным сообщением(время прихода сообщения).

// unWaitTime - время ожидания подтверждения от оператора в миллисекундах.

// Если dwWaitTime равно нулю, то ожидание не выполняется. Если dwWaitTime равно INFINITE,

// то ожидание будет выполняться бесконечно долго.

// Возврат:

// ISuccess - нормальное завершение без ожидания действий оператора.

// IStop - оператор останавливает тестирование.

// IContinue - выполянлось ожидание действий оператора и оператор подтвердил выполнение действий.

// ITimeOut - не было подтверждения от оператора в течении заданного времени.

// IError - ошибка.

IOperations CServer::MsgToOperator( char* szMsgText, void* pData, unsigned unWaitTime )

{

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

m_pIMsgOut->MsgOut( szMsgText, pData, unWaitTime );

IOperations RetValue = ISuccess;

if ( unWaitTime != 0 )

{

HANDLE hEvents[2];

hEvents[0] = m_hStopEvent;

hEvents[1] = m_hContinueEvent;

// Входим в критический раздел.

EnterCriticalSection(&m_CritSection);

m_bWaitOper = TRUE;

// Выходим из критического раздела.

LeaveCriticalSection(&m_CritSection);

// Ждем одно из событий.

DWORD Ret = WaitForMultipleObjects(2, hEvents, FALSE, unWaitTime);

switch ( Ret )

{

case WAIT_OBJECT_0:

// Остановиться!

RetValue = IStop;

break;

case (WAIT_OBJECT_0 + 1):

// Продолжить выполнение.

RetValue = IContinue;

break;

case WAIT_TIMEOUT:

// Истекло ожидание действий оператора.

RetValue = ITimeOut;

break;

default:

// Иное - ошибка.

RetValue = IError;

break;

}

// Входим в критический раздел.

EnterCriticalSection(&m_CritSection);

m_bWaitOper = FALSE;

// Выходим из критического раздела.

LeaveCriticalSection(&m_CritSection);

}

return RetValue;

}

void CServer::GenExeption(char* szMsgText, void* pData)

{

CThrowData MsgData;

MsgData.szMsgText = szMsgText;

MsgData.pData = pData;

throw MsgData;

}

// Метод запуска/возобновления потока.

bool CServer::StartResume(void)

{

if ( !bInit ) return false;

bool Ret = true;

if ( IsThreadResumed() )

{

// Поток остановлен с помощью метода Pause или только что создан -

// запускаем поток.

DWORD ResCount = 1;

while ( ResCount != 0 && ResCount != 0xFFFFFFFF )

{

ResCount = Resume();

}

if ( ResCount == 0xFFFFFFFF )

{

Ret = false;

}

}

else

{

// Поток выполняется - скорее всего он ожидает сообщение от оператора.

// Устанавливаем событие m_hContinueEvent.

if ( !SetEvent(m_hContinueEvent) )

{

Ret = false;

}

}

return Ret;

}

// Метод временной остановки потока.

bool CServer::Pause(void)

{

if ( !bInit ) return false;

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

if ( Suspend() != 0xFFFFFFFF ) return true;

return false;

}

// Метод принудительного завершения потока.

bool CServer::Stop(void)

{

if ( !bInit ) return false;

bool Ret = true;

// Входим в критический раздел.

EnterCriticalSection(&m_CritSection);

if ( m_bWaitOper == TRUE )

{

// Идет ожидание сообщения от оператора - устанавливаем событие останова.

if ( !SetEvent(m_hStopEvent) )

{

Ret = false;

}

}

else

{

// Поток не ждет сообщений от оператора - останавливаем поток.

if ( !Terminate( 100 ) )

{

Ret = false;

}

}

// Выходим из критического раздела.

LeaveCriticalSection(&m_CritSection);

return Ret;

}

#pragma warning (disable: 4800)

// Метод проверки выполнения потока.

bool CServer::IsDoing(void)

{

return IsThreadWork();

}

//DWORD InstanceThread(LPVOID lpvParam);

void CServer::GetAnswerToRequest( LPTSTR chRequest, LPTSTR chReply, LPDWORD cbReplyBytes)

{

MsgToOperator( "Recive data:", NULL );

MsgToOperator( chRequest, NULL );

}

DWORD WINAPI CServer::InstanceThread(LPVOID lpvParam)

{

CHAR chRequest[256];

CHAR chReply[256];

DWORD cbBytesRead, cbReplyBytes, cbWritten;

cbBytesRead = cbReplyBytes = cbWritten = 0;

BOOL fSuccess;

// The thread's parameter is a handle to a pipe instance.

int nSize;

while (1)

{

// Read client requests from the pipe.

fSuccess = ReadFile(

((CServer*)lpvParam)->m_hPipeRead,

&nSize, // buffer to receive data

4, // size of data

&cbBytesRead, // number of bytes read

NULL); // not overlapped I/O

if (! fSuccess || cbBytesRead == 0) continue;

fSuccess = ReadFile(

((CServer*)lpvParam)->m_hPipeRead,

chRequest, // buffer to receive data

nSize, // size of buffer

&cbBytesRead, // number of bytes read

NULL); // not overlapped I/O

if (! fSuccess || cbBytesRead == 0) break;

((CServer*)lpvParam)->GetAnswerToRequest( chRequest, chReply, &cbReplyBytes);

}

// Flush the pipe to allow the client to read the pipe's contents

// before disconnecting. Then disconnect the pipe, and close the

// handle to this pipe instance.

FlushFileBuffers(((CServer*)lpvParam)->m_hPipeRead);

DisconnectNamedPipe(((CServer*)lpvParam)->m_hPipeRead);

CloseHandle(((CServer*)lpvParam)->m_hPipeRead);

return 1;

}

bool CServer::Run( void )

{

try

{

BOOL fConnectedRead, fConnectedWrite;

DWORD dwThreadId;

HANDLE hThread;

LPTSTR lpszPipename = "\\\\.\\pipe\\read";

for (;;)

{

m_hPipeRead = CreateNamedPipe(

"\\\\.\\pipe\\read", // pipe name

PIPE_ACCESS_INBOUND, // read/write access

PIPE_WAIT, // blocking mode

PIPE_UNLIMITED_INSTANCES, // max instances

256, // output buffer size

256, // input buffer size

5000, // client time-out

NULL); // no security attribute

if (m_hPipeRead == INVALID_HANDLE_VALUE)

{

GenExeption("Error INVALID_HANDLE_VALUE", NULL);

}

MsgToOperator( "Создан канал чтения", NULL );

m_hPipeWrite = CreateNamedPipe(

"\\\\.\\pipe\\write", // pipe name

PIPE_ACCESS_OUTBOUND, // read/write access

PIPE_WAIT, // blocking mode

PIPE_UNLIMITED_INSTANCES, // max instances

256, // output buffer size

256, // input buffer size

5000, // client time-out

NULL); // no security attribute

if (m_hPipeWrite == INVALID_HANDLE_VALUE)

{

GenExeption("Error INVALID_HANDLE_VALUE", NULL);

}

MsgToOperator( "Создан канал записи", NULL );

fConnectedRead = ConnectNamedPipe(m_hPipeRead, NULL)?

TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

fConnectedWrite = ConnectNamedPipe(m_hPipeWrite, NULL) ?

TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

if (fConnectedRead)

{

MsgToOperator( "Клиент подключен к каналу Read", NULL );

// Create a thread for this client.

hThread = CreateThread(

NULL, // no security attribute

0, // default stack size

(LPTHREAD_START_ROUTINE) InstanceThread,

(LPVOID) this, // thread parameter

0, // not suspended

&dwThreadId); // returns thread ID

if (hThread == NULL)

{

GenExeption("Error Create Thread", NULL );

}

}

else

{

// The client could not connect, so close the pipe.

MsgToOperator("client could not connect", NULL);

CloseHandle(m_hPipeRead);

}

if (fConnectedWrite)

{

MsgToOperator( "Клиент подключен к каналу Write", NULL );

}

else

{

// The client could not connect, so close the pipe.

MsgToOperator("client could not connect", NULL);

CloseHandle(m_hPipeWrite);

}

WaitForSingleObject( hThread, INFINITE );

}

}

catch(CThrowData MsgData)

{

MsgToOperator( MsgData.szMsgText, MsgData.pData );

}

return true;

}

void CServer::SendRequest(char* pszRequest, int nReplyBytes)

{

LPVOID lpvMessage;

BOOL fSuccess;

DWORD cbWritten;

LPTSTR lpszPipename = "\\\\MAXVELL\\pipe\\read";

lpvMessage = &nReplyBytes;

fSuccess = WriteFile(

m_hPipeWrite, // pipe handle

lpvMessage, // message

4,

&cbWritten, // bytes written

NULL); // not overlapped

if (! fSuccess) return;

lpvMessage = pszRequest;

fSuccess = WriteFile(

m_hPipeWrite, // pipe handle

lpvMessage, // message

nReplyBytes,

&cbWritten, // bytes written

NULL); // not overlapped

if (!fSuccess) return;

}

#pragma warning (default: 4800)

// Конструктор.

CServer::CServer( IMsgOut* pIMsgOut )

:CThread(CREATE_SUSPENDED) // Всегда приостановлен.

{

bInit = true;

m_hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if ( !m_hStopEvent ) bInit = false;

m_hContinueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if ( !m_hContinueEvent ) bInit = false;

m_pIMsgOut = pIMsgOut;

if ( !m_pIMsgOut ) bInit = false;

m_bWaitOper = FALSE;

m_hPipeRead = INVALID_HANDLE_VALUE;

m_hPipeWrite = INVALID_HANDLE_VALUE;

// Инициализируем критическую секцию.

InitializeCriticalSection(&m_CritSection);

}

// Деструктор.

CServer::~CServer()

{

// Останавливаем поток.

EndThread();

// Освобождаем дескрипторы событий.

if ( m_hStopEvent ) CloseHandle(m_hStopEvent);

if ( m_hContinueEvent ) CloseHandle(m_hContinueEvent);

// Удаляем критический раздел.

DeleteCriticalSection(&m_CritSection);

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]