Система распределенного доступа к текстовому документу

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    867,18 Кб
  • Опубликовано:
    2014-04-22
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Система распределенного доступа к текстовому документу

Содержание

Введение

. Разработка системы распределённого доступа к текстовому документу

.1 Анализ требований

.2 Проектирование

.2.1 Проектирование структуры системы

.2.2 Проектирование протокола взаимодействия

.2.3 Проектирование серверной части

.2.4 Проектирование клиентской части

.3 Кодирование

. Тестирование

Заключение

Список использованных источников

Приложения

Введение

Системное программирование - род деятельности, заключающийся в работе над системным программным обеспечением. Основная отличительная черта системного программирования по сравнению с прикладным программированием заключается в том, что результатом последнего является выпуск программного обеспечения, предлагающего определённые услуги пользователям (например, текстовый процессор). В то время как результатом системного программирования является выпуск программного обеспечения, предлагающего сервисы по взаимодействию с операционной системой, что подразумевает сильную зависимость таких программ от операционной системы. Например, средства межпроцессного взаимодействия в ОС Windows и Unix отличаются настолько, что значительную часть работы по написанию приложений под них составляет системное программирование. В частности выделим следующие особенности системного программирования:

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

обычно используется низкоуровневый язык программирования (ассемблер) или близкий к низкому уровню (С/С++).

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

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

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

1. Разработка системы распределённого доступа к текстовому документу

.1 Анализ требований

Разрабатываемая система выполняет задачу распределённого доступа к текстовому документу для его редактирования. Система имеет клиент-серверную архитектуру. К одному серверу может быть подключено множество клиентов.

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

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

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

Разработка будет производиться на языке программирования С++ в среде разработке MS Visual Studio 2005.

.2 Проектирование

.2.1 Проектирование структуры системы

Система распределённого доступа к текстовым документам имеет клиент-серверную архитектуру. Работа системы осуществляется посредством запуска одного сервера и нескольких клиентов.

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

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

Общая схема системы представлена на рисунке 1.

Рисунок 1. Общая схема системы

Серверная и клиентские части системы взаимодействуют через сеть по протоколу TCP/IP. Подробно разработка протокола взаимодействия описана в разделе 1.2.2.

Как серверная, так и клиентская часть системы имеет оконный интерфейс, принятый в ОС Windows. Интерфейс серверной части позволяет загружать, посматривать и сохранять текст документа. Клиентский интерфейс выполняет задачи подключения к серверу и редактирования текста. Подробное описание серверной и клиентской частей комплекса можно найти в разделах 1.2.3 и 1.2.4.

1.2.2 Проектирование протокола взаимодействия

Для взаимодействия между клиентской и серверной частями программной системы разработан протокол взаимодействия на основе протокола TCP/IP.

Разработанный протокол взаимодействия обеспечивает:

подключение клиента к серверу;

приём от сервера исходного текста документа;

передачу на сервер транзакций с изменениями текста;

отключение клиента от сервера.

Соединение между серверной и клиентской частями осуществляется путём подключения клиента к серверному сокету. При подключении клиента, сервер передаёт ему текущую версию текста и сам текст документа.

В дальнейшем, взаимодействие осуществляется путём передачи пакетов специального формата.

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

Таблица 1 - Синтаксис пакетов

Синтаксис пакета

Получатель

Пояснения

TRS[версия][старт] [удалено][добавлено][текст]

Сервер

Передача данных клиентской транзакции. [версия] - номер версии текста, 4 байта. [старт] - порядковый номер первого символа в тексте, затрагиваемого транзакцией, 4 байта. [удалено] - количество удалённых из текста символов, 4 байта. [добавлено] - количество добавленных в текст символов, 4 байта. [текст] - добавленный текст, размер определяется полем [добавлено].

TRC[версия][старт] [удалено][добавлено][текст]

Клиент

Рассылка принятой и обработанной сервером транзакции клиентам. [версия] - номер версии текста, 4 байта. [старт] - порядковый номер первого символа в тексте, затрагиваемого транзакцией, 4 байта. [удалено] - количество удалённых из текста символов, 4 байта. [добавлено] - количество добавленных в текст символов, 4 байта. [текст] - добавленный текст, размер определяется полем [добавлено].

YES

Клиент

Ответ-квитанция сервера об успешности транзакции, инициированной клиентом.

NOT

Клиент

Ответ-квитанция сервера об откате транзакции, инициированной клиентом.


.2.3 Проектирование серверной части

Серверная часть системы реализована в виде диалогового Windows-приложения. Основными функциями сервера являются:

серверное приложение поддерживает загрузку текста, отображение его на экране и сохранение в файл.

сервер должен взаимодействовать одновременно с множеством клиентов.

Окно серверной части представлено на рисунке 2.


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

Для каждого клиента создаётся отдельный поток ThreadProc. В этом потоке выполняется:

подключение клиента и инициализация информации о нём;

приём транзакций от клиента в цикле и реакция на них.

При приёме команды TRS, сервер получает от клиента данные о транзакции, проверяет её на актуальность (путём сравнения версий) и, в зависимости от результата, принимает или отклоняет транзакцию. При приёме транзакции изменяется текст на сервере и транзакция рассылается всем остальным клиентам (команда TRC), а клиент инициировавший транзакцию получает квитанцию YES. При отклонении транзакции клиенту передаётся квитанция об откате транзакции - NOT.

Завершается работа клиентского потока при отключении клиента от сокета.

Количество подключенных клиентов отображается в текстовой строке IDC_CLIENT_NUM в окне сервера. Обновление количества подключенных клиентов, а также текущей версии текста выполняется функцией CDistributedEditorServerDlg::UpdateInformation.

При нажатии на кнопку «Загрузить документ» (функция CDistributedEditorServerDlg::OnBnClickedLoad) открывается диалог выбора файла документа, выполняется текста из выбранного файла и вывод его на экран. Диалог выбора файла изображен на рисунке 3.

При нажатии на кнопку «Сохранить документ» (функция CDistributedEditorServerDlg::OnBnClickedSave) открывается диалог выбора файла для сохранения текста, практически аналогичный изображенному на рисунке 3.

Рисунок 3. Диалог загрузки документа

.2.4 Проектирование клиентской части

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

поле редактирования текста документа;

строку ввода IP-адреса сервера;

кнопку подключения/отключения.

Окно диалога клиентской части изображено на рисунке 4.

Рисунок 4. Окно клиента

Главной функцией клиентской части системы является обработчик события изменения текста в поле редактирования документа. Он реализуется функцией CDistributedEditorClientDlg::OnEnChangeText, формирующей транзакции и отправляющей их на сервер.

Приём ответа сервера на транзакции, а также приём от сервера данных о принятых транзакциях других клиентов системы, осуществляется потоковой функцией ReceiveThread. Эта функция в цикле принимает и обрабатывает пакеты с командами от сервера.

При нажатии на кнопку «Подключиться» производится попытка подключения к серверному сокету по адресу, заданному в поле «IP-адрес сервера». Если это удалось, название кнопки изменяется на «Отключиться».

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

Процесс подключения и отключения реализуется функцией CDistributedEditorClientDlg::OnBnClickedConnect.

.3 Кодирование

Программа была закодирована на языке программирования С++ в среде разработке MS Visual Studio 2005.

Исходный текст программы приведён в приложении А.

2. Тестирование

Правильность работы приложений проверена методом функционального тестирования.

Тестирование проводилось на компьютерах типа IBM PC в операционной системе Windows XP.

Список проводимых тестов:

запуск сервера (см. рис. Б1);

запуск клиента (см. рис. Б2);

загрузка документа (см. рис. Б3);

подключение к серверу (см. рис. Б4);

редактирование текста (см. рис. Б5 и Б6);

сохранение документа (см. рис. Б7).

Результаты тестов приведены в приложении Б.

Заключение

В результате выполнения задания курсового проекта была разработана система распределённого доступа к текстовым документам. Разработка производилась на языке программирования С++ в среде разработки MS Vusial Studio 2005 в операционной системе Windows XP на персональном компьютере IBM PC.

Осуществлено функциональное тестирование разработанного приложения, которое показало корректность его работы.

Приложение А

распределенный доступ текстовый документ

Листинг исходного текста

Сервер

// DistributedEditorServer.h: main header file for the PROJECT_NAME application

//

#pragma once

#ifndef __AFXWIN_H__

#error "include 'stdafx.h' before including this file for PCH"

#endif

#include "resource.h"      // main symbols

// CDistributedEditorServerApp:

// See DistributedEditorServer.cpp for the implementation of this class

//CDistributedEditorServerApp: public CWinApp

{:();

// Overrides:BOOL InitInstance();

// Implementation_MESSAGE_MAP()

};CDistributedEditorServerApp theApp;

// DistributedEditorServerDlg.h: header file

//

#pragma once

// CDistributedEditorServerDlg dialogCDistributedEditorServerDlg: public CDialog

{

// Construction:(CWnd* pParent = NULL);   // standard constructor

// Dialog Data{ IDD = IDD_DISTRIBUTEDEDITORSERVER_DIALOG };:void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

// Implementation:m_hIcon;

// Generated message map functionsBOOL OnInitDialog();_msg void OnPaint();_msg void OnClose();_msg HCURSOR OnQueryDragIcon();_MESSAGE_MAP():_msg void OnBnClickedLoad();_msg void OnBnClickedSave();UpdateInformation();m_Text;

};

// DistributedEditorServer.cpp: Defines the class behaviors for the application.

#include "stdafx.h"

#include "DistributedEditorServer.h"

#include "DistributedEditorServerDlg.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// CDistributedEditorServerApp_MESSAGE_MAP(CDistributedEditorServerApp, CWinApp)_COMMAND(ID_HELP, &CWinApp::OnHelp)_MESSAGE_MAP()

// CDistributedEditorServerApp construction::CDistributedEditorServerApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

}

// The one and only CDistributedEditorServerApp objecttheApp;

// CDistributedEditorServerApp initializationCDistributedEditorServerApp::InitInstance()

{

// InitCommonControlsEx() is required on Windows XP if an application

// manifest specifies use of ComCtl32.dll version 6 or later to enable

// visual styles. Otherwise, any window creation will fail.InitCtrls;.dwSize = sizeof(InitCtrls);

// Set this to include all the common control classes you want to use

// in your application..dwICC = ICC_WIN95_CLASSES;(&InitCtrls);::InitInstance();(!AfxSocketInit())

{(L"Ошибка инициализации библиотеки сокетов");FALSE;

}();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need

// Change the registry key under which our settings are stored

// TODO: You should modify this string to be something appropriate

// such as the name of your company or organization(_T("Local AppWizard-Generated Applications"));dlg;_pMainWnd = &dlg;_PTR nResponse = dlg.DoModal();(nResponse == IDOK)

{

// TODO: Place code here to handle when the dialog is

// dismissed with OK

}if (nResponse == IDCANCEL)

{

// TODO: Place code here to handle when the dialog is

// dismissed with Cancel

}

// Since the dialog has been closed, return FALSE so that we exit the

// application, rather than start the application's message pump.FALSE;

}

// DistributedEditorServerDlg.cpp: implementation file

#include "stdafx.h"

#include "DistributedEditorServer.h"

#include "DistributedEditorServerDlg.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

#define BUFFER_SIZE   32000*MainDlg;    //Указатель на экземпляр класса главного окнаMainThread;                     //Главный поток сервера (подключающий клиентов)MainSocket;                     //Сокет сервераnumsoc = 0;                        //Индекс последнего подключенного клиента::map<int,HANDLE> mapThreads;      //Карта клиентских потоков::map<int,SOCKET> mapSocs;        //Карта клиентских сокетовcsCurrentText = L"";           //Текущая версия документа (текст)iVersion = 0;                    //Текущая версия документа (номер)iClients = 0;                   //Кол-во подключенных клиентов

//Функция клиентского потокаWINAPI ThreadProc(LPVOID lpParam)

{num = (int) lpParam;                        //Индекс клиентаClientSocket = mapSocs.find(num)->second;   //Клиентский сокетbuff[BUFFER_SIZE];           //Буфер для приёма и отправки данныхiLen = 0;                 //Длина принимаемого фрагмента данныхiClientVers = 0;        //Номер клиентской версии документаXb = 0;                    //Кол-во символов от начала текста, не изменённых транзакциейdelS = 0;                 //Кол-во удалённых символовinsS = 0;                 //Кол-во добавленных символов*wText = NULL;         //Указатель на буфер приёма юникодовского текстаcsInsertedBlock;       //Добавленный блок текстаcsNewText;             //Результат транзакции++;>UpdateInformation();(1)    //Цикл приёма команд от клиента

{(buff, BUFFER_SIZE);(recv(ClientSocket, buff, 3, 0)<3);(!strcmp(buff, "CON"))    //Подключение клиента

{

//Передача клиенту текущей версии документа (длины текста, версии и самого текста)= csCurrentText.GetLength();(ClientSocket, (const char *) &iLen, 4, 0);(ClientSocket, (const char *) &iVersion, 4, 0);(iLen)(ClientSocket, (const char *) csCurrentText.GetBuffer(), iLen*sizeof(WCHAR), 0);

}if (!strcmp(buff, "TRS"))   //Обработка транзакции сервером

{

//Приём данных транзакции от клиента(ClientSocket, (char *) &iClientVers, 4, 0);(ClientSocket, (char *) &Xb, 4, 0);(ClientSocket, (char *) &delS, 4, 0);(ClientSocket, (char *) &insS, 4, 0);= (WCHAR*) malloc((insS+1)*sizeof(WCHAR));(wText, (insS+1)*sizeof(WCHAR));(insS)(ClientSocket, (char*) wText, insS*sizeof(WCHAR), 0);= wText;(iClientVers == iVersion) //Сравнение версий (если клиентская версия устарела, транзакция не может пройти)

{

//Транзакция успешна++;(ClientSocket, "YES", 3, 0);    //Уведомление клиента

//Обновление документа= csCurrentText.Left(Xb);+= csInsertedBlock;+= csCurrentText.Right(csCurrentText.GetLength()-Xb-delS);= csNewText;>UpdateInformation();

//Рассылка транзакции остальным клиентам(std::map<int,SOCKET>::iterator it = mapSocs.begin(); it!= mapSocs.end(); it++)(it->second!= ClientSocket)

{(buff, "TRC", 3);(&buff[3], &iVersion, 4);(&buff[7], &Xb, 4);(&buff[11], &delS, 4);(&buff[15], &insS, 4);(insS)

  CopyMemory(&buff[19], csInsertedBlock.GetBuffer(), insS*sizeof(WCHAR));(it->second, buff, insS*sizeof(WCHAR) + 19, 0);

}

}

{

//Откат транзакции(ClientSocket, "NOT", 3, 0);  //Уведомление клиента

}

}

{>MessageBox(L"Нераспознанная команда", NULL, MB_ICONERROR);;

}

//Закрытие сокета и отключение от сервера(ClientSocket);.erase(num);.erase(num);-;>UpdateInformation();0;

}

//Функция потока, подключающего клиентовWINAPI WorkThread(LPVOID lpParam)

{AcceptSocket;(1)    //Бесконечный цикл, подключающий новых клиентов

{= SOCKET_ERROR;(AcceptSocket==SOCKET_ERROR)= accept(MainSocket, NULL, NULL);.insert(std::make_pair(numsoc,AcceptSocket));.insert(std::make_pair(numsoc,CreateThread(NULL,0,&ThreadProc,(void*)numsoc,0,NULL)));++;

}0;

}

// CDistributedEditorServerDlg dialog::CDistributedEditorServerDlg(CWnd* pParent /*=NULL*/)

: CDialog(CDistributedEditorServerDlg::IDD, pParent)

, m_Text(_T(""))

{_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}CDistributedEditorServerDlg::DoDataExchange(CDataExchange* pDX)

{::DoDataExchange(pDX);_Text(pDX, IDC_TEXT, m_Text);

}_MESSAGE_MAP(CDistributedEditorServerDlg, CDialog)_WM_PAINT()_WM_CLOSE()_WM_QUERYDRAGICON()

//}}AFX_MSG_MAP_BN_CLICKED(IDC_LOAD, &CDistributedEditorServerDlg::OnBnClickedLoad)_BN_CLICKED(IDC_SAVE, &CDistributedEditorServerDlg::OnBnClickedSave)_MESSAGE_MAP()

//Функция инициализации диалога (главного окна)CDistributedEditorServerDlg::OnInitDialog()

{_in addr;::OnInitDialog();

// Set the icon for this dialog. The framework does this automatically

// when the application's main window is not a dialog(m_hIcon, TRUE);          // Set big icon(m_hIcon, FALSE);    // Set small icon= (CDistributedEditorServerDlg*) AfxGetApp()->m_pMainWnd;

//Создание сокета= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);(MainSocket==INVALID_SOCKET)

{(L"Не удалось создать сокет", NULL, MB_ICONERROR);FALSE;

}.sin_family = AF_INET;.sin_addr.s_addr = INADDR_ANY;.sin_port = htons(7780);

//Привязка сокета(bind(MainSocket,(SOCKADDR*) &addr,sizeof(addr))==SOCKET_ERROR)

{(L"Ошибка привязки сокета", NULL, MB_ICONERROR);FALSE;

}

//Прослушивание сокета(listen(MainSocket,1)==SOCKET_ERROR)

{(L"Ошибка прослушивания сокета", NULL, MB_ICONERROR);FALSE;

}

//Создание главного потока (подключающего клиентов)= CreateThread(NULL, 0, &WorkThread, NULL, 0, NULL);();TRUE;

}

// If you add a minimize button to your dialog, you will need the code below

// to draw the icon. For MFC applications using the document/view model,

// this is automatically done for you by the framework.CDistributedEditorServerDlg::OnPaint()

{::OnPaint();

}

//Функция закрытия главного окнаCDistributedEditorServerDlg::OnClose()

{(MainThread, 0);(MainSocket);::OnClose();

}

// The system calls this function to obtain the cursor to display while the user drags

// the minimized window.CDistributedEditorServerDlg::OnQueryDragIcon()

{static_cast<HCURSOR>(m_hIcon);

}

//Реакция на нажатие кнопки "Загрузить"CDistributedEditorServerDlg::OnBnClickedLoad()

{file;csFileName;*buffer = NULL;_t *wbuffer = NULL;iLen = 0;(iClients)

{(L"Текст в стадии редактирования. Загрузка невозможна.", NULL, MB_ICONWARNING);;

}

//Диалог выбора файлаfiledlg(TRUE, L"txt", NULL, OFN_OVERWRITEPROMPT, L"Текстовый файл|*.txt||", NULL, 0);(filedlg.DoModal() == IDOK)

{

//Чтение загружаемого файла = filedlg.GetPathName();.Open(csFileName, CFile::modeRead, NULL);= file.GetLength();= (char*) malloc(iLen+sizeof(WCHAR));(buffer, iLen+sizeof(WCHAR));.Read(buffer, iLen);

//Распознавание типа текста(strlen(buffer) == iLen)    //Обычный (Multi-Byte) файл= buffer; //Юникодовский (возможно) файл

{= (wchar_t*) buffer;= wbuffer;

}= 0;();

}

}

//Реакция на нажатие кнопки "Сохранить"CDistributedEditorServerDlg::OnBnClickedSave()

{file;csFileName;

//Диалог выбора файлаfiledlg(FALSE, L"txt", NULL, OFN_OVERWRITEPROMPT, L"Текстовый файл|*.txt||", NULL, 0);(filedlg.DoModal() == IDOK)

{

//Открытие файла и сохранение в него тукущей версии текста= filedlg.GetPathName();.Open(csFileName, CFile::modeCreate | CFile::modeWrite, NULL);.Write(csCurrentText, csCurrentText.GetLength()*sizeof(WCHAR));

}

}

//Обновление элементов диалога (текст и кол-во клиентов)CDistributedEditorServerDlg::UpdateInformation()

{_t NumBuff[12];(IDC_TEXT, csCurrentText);(IDC_CLIENT_NUM, _itow(iClients, NumBuff, 10));

}

Клиент

// DistributedEditorClient.h: main header file for the PROJECT_NAME application

//

#pragma once

#ifndef __AFXWIN_H__

#error "include 'stdafx.h' before including this file for PCH"

#include "resource.h"      // main symbols

// CDistributedEditorClientApp:

// See DistributedEditorClient.cpp for the implementation of this class

//CDistributedEditorClientApp: public CWinApp

{:();

// Overrides:BOOL InitInstance();

// Implementation_MESSAGE_MAP()

};CDistributedEditorClientApp theApp;

// DistributedEditorClientDlg.h: header file

//

#pragma once

#include "afxcmn.h"

// CDistributedEditorClientDlg dialogCDistributedEditorClientDlg: public CDialog

{

// Construction:(CWnd* pParent = NULL);   // standard constructor

// Dialog Data{ IDD = IDD_DISTRIBUTEDEDITORCLIENT_DIALOG };:void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

// Implementation:m_hIcon;

// Generated message map functionsBOOL OnInitDialog();_msg void OnPaint();_msg HCURSOR OnQueryDragIcon();_MESSAGE_MAP():_msg void OnBnClickedConnect();:m_Text;:m_IP;:_msg void OnEnChangeText();

};

// DistributedEditorClient.cpp: Defines the class behaviors for the application.

//

#include "stdafx.h"

#include "DistributedEditorClient.h"

#include "DistributedEditorClientDlg.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// CDistributedEditorClientApp_MESSAGE_MAP(CDistributedEditorClientApp, CWinApp)_COMMAND(ID_HELP, &CWinApp::OnHelp)_MESSAGE_MAP()

// CDistributedEditorClientApp construction::CDistributedEditorClientApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

}

// The one and only CDistributedEditorClientApp objecttheApp;

// CDistributedEditorClientApp initializationCDistributedEditorClientApp::InitInstance()

{

// InitCommonControlsEx() is required on Windows XP if an application

// manifest specifies use of ComCtl32.dll version 6 or later to enable

// visual styles. Otherwise, any window creation will fail.InitCtrls;.dwSize = sizeof(InitCtrls);

// Set this to include all the common control classes you want to use

// in your application..dwICC = ICC_WIN95_CLASSES;(&InitCtrls);::InitInstance();(!AfxSocketInit())

{(L"Ошибка инициализации библиотеки сокетов");FALSE;

}();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need

// Change the registry key under which our settings are stored

// TODO: You should modify this string to be something appropriate

// such as the name of your company or organization(_T("Local AppWizard-Generated Applications"));dlg;_pMainWnd = &dlg;_PTR nResponse = dlg.DoModal();(nResponse == IDOK)

{

// TODO: Place code here to handle when the dialog is

// dismissed with OK

}if (nResponse == IDCANCEL)

{

// TODO: Place code here to handle when the dialog is

// dismissed with Cancel

}

// Since the dialog has been closed, return FALSE so that we exit the

// application, rather than start the application's message pump.FALSE;

}

// DistributedEditorClientDlg.cpp: implementation file

#include "stdafx.h"

#include "DistributedEditorClient.h"

#include "DistributedEditorClientDlg.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

#define BUFFER_SIZE   32000* MainDlg;   //Указатель на экземпляр класса главного окнаClientThread;                //Клиентский потокClientSocket;                //Клиентский сокетbConnected;                     //Флаг подключения к серверуhWaitAnswerEvent;             //Событие ожидания ответа сервераcsCurrentText = L"";           //Текущая версия документа (текст)iVersion = 0;                       //Текущая версия документа (номер)

//Функция клиентского потока (для приёма команд сервера)WINAPI ReceiveThread(LPVOID lpParam)

{(buff, 4);(recv(ClientSocket, buff, 3, 0)<3);(!strcmp(buff, "YES"))    //Уведомление об успешной транзакции

{++;= MainDlg->m_Text;(hWaitAnswerEvent);

}if (!strcmp(buff, "NOT"))  //Уведомление об откате транзакции

{>SetDlgItemText(IDC_TEXT, csCurrentText);(hWaitAnswerEvent);

}if (!strcmp(buff, "TRC"))   //Рассылка транзакции, принятой сервером

{

//Приём данных транзакции(ClientSocket, (char *) &iNewVers, 4, 0);(ClientSocket, (char *) &Xb, 4, 0);(ClientSocket, (char *) &delS, 4, 0);(ClientSocket, (char *) &insS, 4, 0);= (WCHAR*) malloc((insS+1)*sizeof(WCHAR));(wText, (insS+1)*sizeof(WCHAR));(insS)(ClientSocket, (char*) wText, insS*sizeof(WCHAR), 0);= wText;(iNewVers == iVersion + 1)  //Клиентская версия предшествует версии сервера

{++;      //Обновление номера версии

//Обновление текста документа= csCurrentText.Left(Xb);+= csInsertedBlock;+= csCurrentText.Right(csCurrentText.GetLength()-Xb-delS);= csNewText;>SetDlgItemText(IDC_TEXT, csCurrentText);

}        //Клиентская версия либо устарела, либо её значение ошибочно

{>MessageBox(L"Ошибка синхронизации версий", NULL, MB_ICONERROR);;

}

}

{>MessageBox(L"Нераспознанная команда", NULL, MB_ICONERROR);;

}

}

//Закрытие сокета и отключение клиента(ClientSocket);= false;>m_IP.EnableWindow(true);>SetDlgItemText(IDC_CONNECT, L"Подключиться");0;

}

// CDistributedEditorClientDlg dialog::CDistributedEditorClientDlg(CWnd* pParent /*=NULL*/)

: CDialog(CDistributedEditorClientDlg::IDD, pParent)

, m_Text(_T(""))

{_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}CDistributedEditorClientDlg::DoDataExchange(CDataExchange* pDX)

{::DoDataExchange(pDX);_Text(pDX, IDC_TEXT, m_Text);_Control(pDX, IDC_IPADDRESS, m_IP);

}_MESSAGE_MAP(CDistributedEditorClientDlg, CDialog)_WM_PAINT()_WM_QUERYDRAGICON()

//}}AFX_MSG_MAP_BN_CLICKED(IDC_CONNECT, &CDistributedEditorClientDlg::OnBnClickedConnect)_EN_CHANGE(IDC_TEXT, &CDistributedEditorClientDlg::OnEnChangeText)_MESSAGE_MAP()

//Функция инициализации диалога (главного окна)CDistributedEditorClientDlg::OnInitDialog()

{::OnInitDialog();

// Set the icon for this dialog. The framework does this automatically

// when the application's main window is not a dialog(m_hIcon, TRUE);          // Set big icon(m_hIcon, FALSE);    // Set small icon= (CDistributedEditorClientDlg*) AfxGetApp()->m_pMainWnd;_IP.SetAddress(127,0,0,1);= false;TRUE;

}

// If you add a minimize button to your dialog, you will need the code below

// to draw the icon. For MFC applications using the document/view model,

// this is automatically done for you by the framework.CDistributedEditorClientDlg::OnPaint()

{::OnPaint();

}

// The system calls this function to obtain the cursor to display while the user drags

// the minimized window.CDistributedEditorClientDlg::OnQueryDragIcon()

{static_cast<HCURSOR>(m_hIcon);

}

//Функция реакции на нажатие кнопки Подключиться/ОтключитьсяCDistributedEditorClientDlg::OnBnClickedConnect()

{ip;iLen = 0;*wText = NULL;(!bConnected) //Клиент не подключен

{(true);

//Создание сокета= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);(ClientSocket==INVALID_SOCKET)

{(L"Не удалось создать сокет", NULL, MB_ICONERROR);;

}_in addr;.sin_family = AF_INET;_IP.GetAddress(ip);.sin_addr.s_addr = htonl(ip);.sin_port = htons(7780);

//Подключение к серверу(connect(ClientSocket, (SOCKADDR*) &addr, sizeof(addr))==SOCKET_ERROR)

{(L"Ошибка подключения к серверу", NULL, MB_ICONERROR);;

}

//Отправка команды подключения и приём текущей версии документа(ClientSocket, "CON", 3, 0);(ClientSocket, (char*) &iLen, 4, 0);(ClientSocket, (char*) &iVersion, 4, 0);= (WCHAR*) malloc((iLen+1)*sizeof(WCHAR));(wText, (iLen+1)*sizeof(WCHAR));(iLen)

{iRecvBytes = 0;

{+= recv(ClientSocket, (char*) (((DWORD)wText) + iRecvBytes), iLen*sizeof(WCHAR) - iRecvBytes, 0);

}(iRecvBytes < iLen*sizeof(WCHAR));

}= wText;(IDC_TEXT, wText); //Вывод текущей версии в окне= true;= CreateEvent(NULL, TRUE, TRUE, L"WaitAnswerEvent");

//Создание клиентского потока (для приёма команд сервера)= CreateThread(NULL, 0, &ReceiveThread, NULL, 0, NULL);_IP.EnableWindow(false);(IDC_CONNECT, L"Отключиться");

}        //Клиент подключен

{

//Отключение от сервера(ClientThread, 0);(ClientSocket);= false;_IP.EnableWindow(true);(IDC_CONNECT, L"Подключиться");

}

}

//Функция реакции на событие изменения текста документаCDistributedEditorClientDlg::OnEnChangeText()

{(bConnected)

{(hWaitAnswerEvent);(true);Xb = 0;                            //Кол-во символов от начала текста, не изменённых транзакциейXe = 0;                             //Кол-во символов от конца текста, не изменённых транзакциейLnew = m_Text.GetLength();          //Длина изменённого текстаLold = csCurrentText.GetLength();    //Длина первоначального текстаiTemp = 0;                        //Длина промежуточной строкиcsTemp;                          //Промежуточная строкаbuffer[BUFFER_SIZE];            //Аккумулирующий буфер (для передачи всей транзакции одним блоком)

//Вычисление кол-ва символов от начала текста, не изменённых транзакцией(m_Text.Mid(Xb, 1) == csCurrentText.Mid(Xb, 1))++;

//Определение типа транзакции((Xb<Lnew) && (Xb<Lold)) //Транзакция, заменяющая фрагмент текста (в любом месте текста)

{

//Вычисление кол-ва символов от конца текста, не изменённых транзакцией((m_Text.Mid(Lnew-Xe-1, 1) == csCurrentText.Mid(Lold-Xe-1, 1)) && (Xe < Lold - Xb) && (Xe < Lnew - Xb))++;(buffer, "TRS", 3);(&buffer[3], &iVersion, 4);(&buffer[7], &Xb, 4);= Lold - Xb - Xe;     //Кол-во удалённых символов(&buffer[11], &iTemp, 4);= Lnew - Xb - Xe;       //Кол-во добавленных символов(&buffer[15], &iTemp, 4);= m_Text.Mid(Xb, iTemp);(&buffer[19], csTemp.GetBuffer(), iTemp*sizeof(WCHAR));

//Отправка данных транзакции(ClientSocket, buffer, iTemp*sizeof(WCHAR) + 19, 0);

}if ((Xb<Lnew) && (Xb==Lold))   //Транзакция, добавляющая фрагмент в конец текста

{(buffer, "TRS", 3);(&buffer[3], &iVersion, 4);(&buffer[7], &Xb, 4);= 0;              //Кол-во удалённых символов(&buffer[11], &iTemp, 4);= Lnew - Xb;      //Кол-во добавленных символов(&buffer[15], &iTemp, 4);= m_Text.Right(iTemp);(&buffer[19], csTemp.GetBuffer(), iTemp*sizeof(WCHAR));

}if ((Xb==Lnew) && (Xb<Lold))   //Транзакция, удаляющая фрагмент в конце текста

{(buffer, "TRS", 3);(&buffer[3], &iVersion, 4);(&buffer[7], &Xb, 4);= Lold - Xb;     //Кол-во удалённых символов(&buffer[11], &iTemp, 4);= 0;             //Кол-во добавленных символов(&buffer[15], &iTemp, 4);

//Отправка данных транзакции(ClientSocket, buffer, 19, 0);

}

//Ожидание ответа сервера на транзакцию(WaitForSingleObject(hWaitAnswerEvent, 5000) == WAIT_TIMEOUT)(L"Не удалось дождаться ответа сервера на транзакцию.", L"Ошибка", MB_ICONERROR);

}

}

Приложение Б

Тестирование

Рисунок Б1 - Запуск сервера

Рисунок Б2 - Запуск клиента

Рисунок Б3 - Загрузка документа

Рисунок Б4 - Подключение клиента

Рисунок Б5 - Редактирование текста. Клиент

Рисунок Б6 - Редактирование текста. Сервер

Рисунок Б7 - Сохранение документа в файл


Приложение В

диаграммы

Рисунок В1 - Диаграмма вариантов использования

Рисунок В2 - Диаграмма кооперации

Рисунок В3 - Диаграмма деятельности. Формирование транзакции клиентом

Рисунок В4 - Диаграмма деятельности. Обработка транзакции сервером

Рисунок В5 - Диаграмма последовательности

Похожие работы на - Система распределенного доступа к текстовому документу

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!