Создание клиент-серверного приложения

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

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 22.08.2016
Размер файла 4,7 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

Введение

На сегодняшний день существует большое количество протоколов, предназначенных для обмена мгновенными сообщениями, создано огромное количество серверов и клиентов, обеспечивающих работу по этим протоколам. Однако, большинство из этих протоколов закрыты или открыты, но не полностью. Это в первую очередь чревато тем, что владелец такого протокола может в любой момент внести изменения в свой протокол, после чего альтернативные клиенты перестанут корректно работать. Такая ситуация наблюдалась на протоколах OSCAR/ICQ и Skype. Второй, не менее важной проблемой является то, что эти протоколы зачастую громоздки (вследствие огромного количества дополнительных возможностей, вплоть до голосовой и видеосвязи), а, следовательно, избыточны для деловой переписки.

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

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

1. Постановка задачи

Для решения поставленной задачи необходимо создать клиент-серверное приложение, которое должно обеспечить:

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

- передачу файлов от клиента к клиенту, управление процессом передачи;

- сохранение сообщений на сервере в случае невозможности мгновенной доставки адресату (например, по причине его отсутствия в сети), с последующей выдачей их при возобновлении доступности адресата (по его запросу);

- авторизацию клиента (сотрудника) на сервере безопасным способом (без возможности перехвата пароля);

- смену пароля клиента (сотрудника), статуса и базовой пользовательской информации (хранимой на сервере и выдаваемой по запросу);

- хранение и выдачу списка собеседников (сотрудников) по запросу клиента;

- оповещение всех других клиентов (сотрудников), активных на данный момент, о добавлении нового сотрудника, удалении сотрудника, смене пользовательской информации;

- возможность (с помощью специального администрирующего клиента):

1) получать администратору (root) доступ к серверу безопасным способом;

2) менять пароль администратора по запросу;

3) создавать, переименовывать и удалять группы сотрудников;

4) менять принадлежность группы или сотрудника к другой группе;

5) создавать и удалять UIN'ы сотрудников, сбрасывать пароль с UIN'а;

6) удалять непрочитанные сообщения с сервера в случае потери их актуальности (для группы UIN'ов или только для одного конкретного);

7) выключить сервер.

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

Система должна быть платформонезависимой (относительно Windows, Linux), а, следовательно, должна быть разработана с использованием кросс-платформенного инструментария.

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

- сервер - программа, принимающая запросы от клиентов;

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

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

Основные возможности сервера:

- безопасная аутентификация учётных записей;

- хранение списка контактов пользователей на сервере с возможностью группировки по группам/отделам/подразделениям;

- поддержка и хранение offline-сообщений с возможностью последующей доставки по запросу;

- мгновенная передача сообщений;

- передача файлов;

- хранение анкетных данных пользователей;

- рассылка статусов присутствия пользователей;

- удалённое администрирование сервера;

- рассылка системные сообщения всем пользователям.

Основные возможности клиента:

- серверный список контактов с поддержкой иерархии групп;

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

- мгновенная передача сообщений с подтверждением о доставке;

- форматирование отправляемых сообщений;

- встроенная поддержка прозрачного шифрования сообщений;

- передача файлов и управление процессом;

- поддержка всплывающих уведомлений и сообщений;

- продуманный и удобный пользовательский интерфейс;

- запуск свернутым в системный лоток с автоматическим подключением к серверу;

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

- смена анкетных данных пользователя.

Основные возможности администрирующего клиента:

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

- добавление и удаление сотрудников;

- сброс пароля с UIN;

- смена принадлежности группы/сотрудника другой родительской группе;

- удаление непрочитанных сообщений для группы или отдельного сотрудника;

- смена пароля администратора;

- выключение сервера.

2. Исследование предметной области

2.1 Обзор существующих технологических решений

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

- OBIMP - открытый протокол, используемый системой Bimoid (клиент + сервер) [1]. Bimoid разработан исключительно под Windows (клиент может быть запущен с использованием стороннего WinAPI - например, wine), и не удовлетворяет требованию кросс-платформенности.

- IRC - открытый протокол прикладного уровня для обмена сообщениями в режиме реального времени [2]. Разработан в основном для группового общения, также позволяет общаться через личные сообщения и обмениваться данными, в том числе файлами. Текстовый протокол, предполагает отправку по сети большого количества текстовой информации, что ведет к чрезмерному расходованию трафика. Однако протокол достаточно прост для реализации, существуют готовые бесплатные клиенты и сервера, реализующие IRC. Некоторые коммерческие организации используют преимущества IRC при проведении распределенных совещаний. Но при этом следует учитывать, что передаваемая информация не защищена, и некоторые компании предпочитают использование более надежных в этом отношении средств.

- XMPP (ранее известный как Jabber) - расширяемый, открытый, свободный для использования протокол мгновенного обмена сообщениями и информацией о присутствии в режиме, близком к режиму реального времени, основанный на XML [3]. Используется огромным количеством разнообразных клиентов и серверов, иногда - в модифицированном виде. Самые распространенные реализации - серверы: Одноклассники.ru, ВКонтакте, Я.Онлайн, Google Talk, QIP, Facebook и многие другие; клиенты: pidgin, empathy, qutIM, gajIM, psi, adium, kopete, mirandaIM, QIP 2012 и многие другие. Слабыми сторонами протокола являются избыточность передаваемой информации и неэффективность передачи бинарных данных.

- OSCAR - открытый (с 5 марта 2008 года), но не свободный сетевой протокол, обеспечивающий обмен мгновенными и оффлайновыми текстовыми сообщениями [4]. В данный момент используется для двух систем: AIM (компания AOL, управляемая Time Warner) и ICQ (компания Mail.Ru Group). Обмен мгновенными сообщениями осуществляется посредством специальных пакетов, содержащих сообщение и служебную информацию. Достаточно мощный протокол и на сегодняшний день предоставляет возможности голосовой и видеосвязи, отправки SMS и многое другое, вследствие чего имеет сложную и избыточную для решаемой задачи структуру пакета.

- Gadu-Gadu - проприетарный протокол и программа-клиент для мгновенного обмена сообщениями в одноимённой сети для Microsoft Windows. Авторы Gadu-Gadu официально запрещают сторонним приложениям использовать их протокол для доступа к их серверам.

- Skype, MySpace, QQ и другие - закрытые протоколы, используемые в клиентах и серверах, разрабатываемых коммерческими организациями. Данные организации регулярно вносят изменения в свои протоколы, после чего альтернативные (сторонние) клиенты перестают работать на этих протоколах. Ранее подобная ситуация неоднократно наблюдалась и на протоколе OSCAR (ICQ).

2.2 Обоснование выбора собственного технологического решения

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

Для разработки клиент-серверного приложения в качестве инструментария целесообразно выбрать язык С++ с использованием программного интерфейса Socket API (для Windows - Winsock), набора компонентов для создания графического интерфейса Qt Framework 4.х и библиотеки криптографических алгоритмов Crypto++. Данный инструментарий, при условии соблюдения всех требований к функциональности и эффективности разрабатываемого приложения, обеспечит следующие достоинства:

- аутентификация с использованием криптографического алгоритма RSA обеспечивает необходимый уровень безопасности в системе;

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

- передача файлов посредством собственного сервера исключает необходимость использования сторонних сервисов;

- простота реализации отдельных компонентов системы и отсутствие перегруженности разрабатываемого протокола возможностями, ненужными для корпоративной переписки (и свойственными другим, более известным протоколам данной области - OSCAR, Jabber), позволяет снизить нагрузку как на компьютер, выступающий в роли сервера, так и компьютеры клиентов (сотрудников);

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

2.3 Описание выбранных средств разработки

клиент серверный приложение

2.3.1 Языки программирования

C++ -- компилируемый статически типизированный язык программирования общего назначения [5]. Он поддерживает такие парадигмы программирования как процедурное программирование, объектно-ориентированное программирование, обобщенное программирование, обеспечивает модульность, раздельную компиляцию, обработку исключений, абстракцию данных, объявление типов (классов) объектов, виртуальные функции. Стандартная библиотека включает, в том числе, общеупотребительные контейнеры и алгоритмы. C++ сочетает свойства как высокоуровневых, так и низкоуровневых языков. В сравнении с его предшественником -- языком C, -- наибольшее внимание уделено поддержке объектно-ориентированного и обобщённого программирования.

Являясь одним из самых популярных языков программирования, C++ широко используется для разработки программного обеспечения. Область его применения включает создание операционных систем, разнообразных прикладных программ, драйверов устройств, приложений для встраиваемых систем, высокопроизводительных серверов, а также развлекательных приложений (игр). Существует множество реализаций языка C++, как бесплатных, так и коммерческих и для различных платформ. Например, на платформе x86 это GCC, Visual C++, Intel C++ Compiler, Embarcadero (Borland) C++ Builder и другие.

Синтаксис C++ унаследован от языка C. Одним из принципов разработки было сохранение совместимости с C. Тем не менее, C++ не является в строгом смысле надмножеством C; множество программ, которые могут одинаково успешно транслироваться как компиляторами C, так и компиляторами C++, довольно велико, но не включает все возможные программы на C.

HTML (англ. сокр. HyperText Markup Language - язык гипертекстовой разметки). На этом языке браузеру сообщается, какой именно текст и другие элементы (картинки, таблицы, формы) и каким образом нужно отображать на странице. На языке HTML не программируют, а верстают - особым образом размечают текст для публикации в интернете.

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

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

2.3.2 Технологии

Понятие сокета.

Сомкеты -- название программного интерфейса для обеспечения обмена данными между процессами [6]. Процессы при таком обмене могут исполняться как на одной ЭВМ, так и на различных ЭВМ, связанных между собой сетью. Сокет -- абстрактный объект, представляющий конечную точку соединения.

Следует различать клиентские и серверные сокеты. Клиентские сокеты грубо можно сравнить с оконечными аппаратами телефонной сети, а серверные -- с коммутаторами. Клиентское приложение (например, браузер) использует только клиентские сокеты, а серверное (например, веб-сервер, которому браузер посылает запросы) -- как клиентские, так и серверные сокеты.

Рисунок 2.1 - Взаимодействие процессов при помощи TCP-сокетов

Интерфейс сокетов впервые появился в BSD Unix. Программный интерфейс сокетов описан в стандарте POSIX.1 и в той или иной мере поддерживается всеми современными операционными системами.

Принцип работы сокетов.

Каждый процесс может создать слушающий сокет (серверный сокет) и привязать его к какому-нибудь порту операционной системы (в UNIX непривилегированные процессы не могут использовать порты меньше 1024). Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения. При этом сохраняется возможность проверить наличие соединений на данный момент, установить тайм-аут для операции и т.д.

Каждый сокет имеет свой адрес. ОС семейства UNIX могут поддерживать много типов адресов, но обязательными являются INET-адрес и UNIX-адрес. Если привязать сокет к UNIX-адресу, то будет создан специальный файл (файл сокета) по заданному пути, через который смогут сообщаться любые локальные процессы путём чтения/записи из него (см. Доменный сокет Unix). Сокеты типа INET доступны из сети и требуют выделения номера порта.

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

Рисунок 2.2 - Клиентский сокет, впускающий сокет и сокет соединения

Berkly Sockets API.

Сокеты Беркли -- интерфейс программирования приложений (API), представляющий собой библиотеку для разработки приложений на языке Си с поддержкой межпроцессного взаимодействия (IPC), часто применяемый в компьютерных сетях [7].

API сокетов Беркли сформировал de facto стандарт абстракции для сетевых сокетов. Большинство прочих языков программирования используют интерфейс, схожий с API языка Си.

Интерфейс сокета Беркли -- API, позволяющий реализацию взаимодействия между компьютерами или между процессами на одном компьютере. Данная технология может работать с множеством различных устройств ввода/вывода и драйверов, несмотря на то, что их поддержка зависит от реализации операционной системы. Подобная реализация интерфейса лежит в основе TCP/IP, благодаря чему считается одной из фундаментальных технологий, на которых основывается Интернет. Технология сокетов впервые была разработана в Калифорнийском университете Беркли для применения на Юникс-системах. Все современные операционные системы имеют ту или иную реализацию интерфейса сокетов Беркли, так как это стало стандартным интерфейсом для подключения к сети Интернет.

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

Winsock.

Windows Sockets API (WSA, также известный как Winsock) - это техническая спецификация, которая определяет, как сетевое программное обеспечение Windows будет получать доступ к сетевым сервисам, в том числе, TCP/IP [8]. Он определяет стандартный интерфейс между клиентским приложением (таким как FTP клиент или веб-браузер) и внешним стеком протоколов TCP/IP. Он основывается на API модели сокетов Беркли, использующейся в BSD для установки соединения между программами.

Qt Framework.

Qt -- кросс-платформенный инструментарий разработки ПО на языке программирования C++ [9]. Есть также «привязки» ко многим другим языкам программирования.

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

Существуют версии библиотеки для Microsoft Windows, систем класса UNIX с графическими подсистемами X11 и Wayland, iOS, Android, Mac OS X, Microsoft Windows CE, QNX, встраиваемых Linux-систем и платформы S60. В данный момент рассматривается возможность внедрения поддержки Qt в Windows Phone. Также идёт портирование на Haiku.

Начиная с версии 4.5 Qt распространяется по 3 лицензиям (независимо от лицензии, исходный код Qt один и тот же):

- Qt Commercial -- для разработки ПО с собственнической лицензией, допускающая модификацию самой Qt без раскрытия изменений;

- GNU GPL -- для разработки ПО с открытыми исходниками, распространяемыми на условиях GNU GPL;

- GNU LGPL -- для разработки ПО с собственнической лицензией, но без внесения изменений в Qt.

Со времени своего появления в 1996 году библиотека Qt легла в основу тысяч успешных проектов во всём мире. Кроме того, Qt является фундаментом популярной рабочей среды KDE, входящей в состав многих дистрибутивов Linux.

Отличительная особенность Qt от других библиотек -- использование Meta Object Compiler (MOC) -- предварительной системы обработки исходного кода (в общем-то, Qt -- это библиотека не для чистого C++, а для его особого наречия, с которого и «переводит» MOC для последующей компиляции любым стандартным C++ компилятором). MOC позволяет во много раз увеличить мощь библиотек, вводя такие понятия, как слоты и сигналы. Утилита MOC ищет в заголовочных файлах на C++ описания классов, содержащие макрос Q_OBJECT, и создаёт дополнительный исходный файл на C++, содержащий метаобъектный код. Схема создания исполняемого модуля [10] представлена на рисунке 2.3.

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

Рисунок 2.3 - Схема создания исполняемого модуля в Qt 4.x

Qt комплектуется визуальной средой разработки графического интерфейса «Qt Designer», позволяющей создавать диалоги и формы в режиме WYSIWYG. В поставке Qt есть «Qt Linguist» -- графическая утилита, позволяющая упростить локализацию и перевод программы на многие языки; и «Qt Assistant» -- справочная система Qt, упрощающая работу с документацией по библиотеке, а также позволяющая создавать кросс-платформенную справку для разрабатываемого на основе Qt ПО. Начиная с версии 4.5.0 в комплект Qt включена среда разработки «Qt Creator», которая включает в себя редактор кода, справку, графические средства «Qt Designer» и возможность отладки приложений. «Qt Creator» может использовать GCC или Microsoft VC++ в качестве компилятора и GDB в качестве отладчика. Для Windows версий библиотека комплектуется компилятором, заголовочными и объектными файлами MinGW.

Crypto++

Crypto++ (также известный как CryptoPP, libcrypto++, и libcryptopp) - свободная и открытая библиотека классов С++, содержащая криптографические алгоритмы и схемы, написанная Wei Dai [11]. Crypto++ широко используется в научных, учебных проектах, открытых и некоммерческих проектах, а также коммерческих. Созданная в 1995 году, библиотека полностью поддерживает 32-битные и 64-битные архитектуры для большинства операционных систем, включая Apple (Mac OS X и iOS), BSD, Linux, Solaris, и Windows. Проект также поддерживает компиляцию под различными компиляторами и IDE, включая Borland Turbo C++, Borland C++ Builder, Clang, CodeWarrior Pro, GCC (ключая Apple GCC), Intel C++ Compiler (ICC), Microsoft Visual C/C++, и Sun Studio.

Из этой библиотеки для решения поставленной задачи окажутся полезными: реализация криптографического алгоритма RSA [12], блокового шифра Rijndael [13], а также хэш-функции MD5 (для проверки корректности отправленного файла на принимающей стороне).

В качестве IDE была выбрана среда разработки Qt Creator 2.6, в качестве компиляторов - GCC 4.7 (Linux) и MinGW 4.4 (Windows). Для сборки установщика будет использоваться NSIS (Nullsoft Scriptable Install System) 2.46 (Windows). Для ОС Linux будут собраны deb-пакеты.

3. Описание разработки

3.1 Протокол LIMone

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

Размещено на http://www.allbest.ru/

Рисунок 3.1 - Структура пакета

Заголовок пакета HEADER содержит следующие поля:

- 0x3C - cтарт-байт, 8 бит;

- Type - тип пакета, определяет его назначение, 16 бит;

- PackNum - номер пакета, 16 бит;

- Length - длина тела пакета (BODY), 16 бит.

Таким образом, размер заголовка пакета равен 56 бит (7 байт), а размер тела пакета не может превышать 65535 байт.

Тип пакета состоит из непосредственно типа (первые 8 бит) и подтипа (следующие 8 бит), определяющего выполняемую операцию.

Для протокола определены следующие типы и подтипы:

- GENERAL - основные операции:

- ROOT_AUTHORIZATION - запрос администратора на авторизацию;

- CHANGE_ROOT_PASSWORD - запрос администратора на смену пароля;

- RESET_UIN_PASSWORD - запрос на сброс пароля с UIN;

- SHUTDOWN_SERVER - запрос на выключение сервера;

- SERVER_PUBLIC_KEY - открытый ключ сервера (RSA);

- AUTHORIZATION - авторизация сотрудника и управление учетной записью:

- AUTHORIZATION_UIN - авторизация сотрудника;

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

- CHANGE_USER_INFO - запрос на смену пользовательской информации;

- GET_USER_INFO - запрос на получение пользовательской информации;

- CHANGE_USER_STATUS - запрос на смену статуса;

- CONTACT_LIST - операции с контакт-листом:

- GET_GROUP_LIST - запрос на получение списка групп;

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

- CREATE_USER - запрос на создание нового сотрудника;

- DELETE_USER - запрос на удаление сотрудника;

- CREATE_GROUP - запрос на создание новой группы;

- ATTACH_TO_GROUP - запрос на изменение родительской группы;

- RENAME_GROUP - запрос на переименование группы;

- DELETE_GROUP - запрос на удаление группы;

- MESSAGES - отправка сообщений и файлов:

- GET_MESSAGE_KEY - запрос на получение секретного ключа для шифрования сообщений (Rijndael);

- SEND_MESSAGE - запрос на передачу текстового сообщения;

- RECV_MESSAGE - входящее текстовое сообщение;

- GET_UNREAD_MESSAGES - запрос на получение непрочитанных сообщений;

- DELETE_UNREAD_MESS - запрос на удаление непрочитанных сообщений;

- SEND_FILE_REQUEST - запрос на отправку файла;

- SEND_FILE_ACCEPT - подтверждение приема файла;

- SEND_FILE_PART - запрос на передачу порции файла;

- FILE_SENDER_CHANNEL - канал отправителя файла;

- FILE_RECEIVER_CHANNEL - канал получателя файла.

Некоторые из операций доступны только администратору, например, модификация контакт-листа, сброс пароля с UIN, выключение сервера и т.д.

Работа по протоколу осуществляется в рамках механизма «запрос клиента - ответ сервера». Для того чтобы клиент мог сопоставить отправленный запрос с полученным ответом, предназначено поле PackNum. Соответствие достигается тем, что сервер обязан указать в ответе тот же номер пакета, который указан в заголовке запроса. Номер пакета начинается с 1 и инкрементируется на стороне клиента после отправки очередного запроса; при достижении максимального значения вновь сбрасывается до 1. Пакеты с номером, равным 0 - пакеты, отправляемые по инициативе сервера (например, оповещения).

Тело пакета (BODY) состоит из TLV. TLV (Tag-Length-Value) - структура, в которой tag определяет назначение данных, length - длину значения, value - непосредственно значение. На tag и length отведено по 16 бит на каждый. Полный список тегов, используемых в протоколе, и их назначение расположены в файле protocol.h.

В протоколе определены 5 возможных статусов сотрудника:

- OFFLINE - «Не в сети»;

- ONLINE - «В сети»;

- BUSY - «Занят»;

- ABSENT - «Отошел»;

- INACCESSIBLE - «Недоступен».

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

<Тип_пакета>::<Подтип_пакета>(TLV(<Тег_1>, <Длина_1>, <Тип_значения_1>) + … + TLV(<Тег_N>, <Длина_N>, <Тип_значения_N>)).

В протоколе для использования внутри TLV определены следующие типы данных:

- TAG - непосредственно тег в структуре, 16 бит;

- STATUS - статус сотрудника, 16 бит;

- GROUP_ID - идентификатор группы, 16 бит;

- FILE_ID - идентификатор сессии передачи файла, 16 бит;

- FSIZE - размер файла, 64 бита;

- FPART_NUMBER - номер порции файла, 32 бита;

- uint<8|16|32|64> - значение размером 8, 16, 32 или 64 бит;

- string - строка символов в кодировке UTF-8;

- array - массив байтов.

Например, запись:

AUTHORIZATION::AUTHORIZATION_UIN(TLV(UIN, 8, string) +

TLV(PASSWORD, L, array))

означает, что данный пакет является запросом на авторизацию сотрудника (тип - AUTHORIZATION, подтип - AUTHORIZATION_UIN); его тело содержит две структуры TLV: первая - UIN - содержит строку из 8 символов, вторая - PASSWORD - содержит массив длинной L. Длина значения может быть не указана в случае, когда она подразумевается, либо не может быть известна заранее. Если ни длина, ни значение не указаны, то TLV является пустым, т.е. длина равна 0, а значение - отсутствует.

В рамках протокола определены несколько схем взаимодействия. К основным схемам относятся:

- Схема аутентификации;

- Схема передачи текстового сообщения;

- Схема отправки файла.

К сервисным схемам взаимодействия относятся:

- Схемы модификации контакт-листа, описывающие операции по созданию, перемещению и удалению групп и сотрудников, а также по переименованию групп;

- Схемы управления работой сервера, описывающие операции по смене пароля администратора, сбросу пароля для сотрудника, удалению непрочитанных сообщений и выключению сервера;

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

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

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

Схема аутентификации администратора отличается от данной схемы лишь тем, что от клиента вместо пакета:

AUTHORIZATION::AUTHORIZATION_UIN(TLV(UIN, 8, string) +

TLV(PASSWORD, array))

высылается пакет:

GENERAL::ROOT_AUTHORIZATION(TLV(PASSWORD, array)).

Кроме того, администрирующему клиенту не нужен ключ AESKey, т.к. этот клиент не занимается отправкой сообщений.

Рисунок 3.2 - Схема аутентификации клиента

На рисунке 3.3 представлена схема передачи текстового сообщения сотруднику. В данной схеме предполагается, что текстовое сообщение передается одному сотруднику. При необходимости отправки текстового сообщения группе в пакете MESSAGES::SEND_MESSAGE вместо TLV(UIN, …) следует указывать TLV(GROUP_ID, …), где GROUP_ID - группа, сотрудникам которой будет разослано сообщение.

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

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

Рисунок 3.3 - Схема передачи текстового сообщения сотруднику

Схема отправки файла состоит из двух схем: схемы отправки запроса на передачу файла и схемы передачи части файла. Схема отправки запроса на передачу файла представлена на рисунке 3.4. Данная схема описывает способ создания сессии передачи файла, посредником в которой является сервер. Запись вида "<= Package <=" или "=> Package =>" означает пересылку полученного пакета без каких-либо модификаций. Согласно протоколу, от получателя требуется согласие на прием файла. Если получатель откажется принимать файл, то серверу будет выслана некритическая ошибка, содержащая причину отказа. Созданная сессия будет удалена из списка, а этот пакет будет переслан на сторону отправителя.Каждая часть файла в этой схеме нумеруется, начиная с 0, и указывается в TLV(FILE_PART, …). Получатель проверяет последовательность номеров частей, и если хотя бы одна из частей файла была утеряна в канале связи, то получатель вышлет сообщение об ошибке в виде пакета:

MESSAGES::FILE_RECEIVER_CHANNEL(TLV(FILE_ID, FILE_ID) +

TLV(ERRORS, string))

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

Если ошибка возникнет на стороне отправителя, то он вышлет пакет:

MESSAGES::FILE_SENDER_CHANNEL(TLV(FILE_ID, FILE_ID) +

TLV(ERRORS, string))

получив который, сервер отменит сеанс передачи файла.

Если получатель пожелает отменить загрузку файла, то он будет должен отправить пакет вида:

MESSAGES::FILE_RECEIVER_CHANNEL(TLV(FILE_ID, FILE_ID) + TLV(CANCEL)).

Отмена отправки файла со стороны отправителя осуществляется отправкой пакета:

MESSAGES::FILE_SENDER_CHANNEL(TLV(FILE_ID, FILE_ID) + TLV(CANCEL)).

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

На рисунке 3.6 представлены схемы модификации контакт-листа. С помощью этих сервисных схем администрирующий клиент может создавать, перемещать и удалять группы и сотрудников, а также переименовывать группы. Для перемещения группы необходимо в запросе CONTACT_LIST::ATTACH_TO_GROUP вместо TLV(UIN, …) указать TLV(GROUP_ID) с идентификатором перемещаемой группы.

Рисунок 3.4 - Схема отправки запроса на передачу файла

Схема передачи части файла изображена на рисунке 3.5.

Рисунок 3.5 - Схема передачи части файла

На рисунке 3.7 представлены схемы управления работой сервера. Эти схемы также относятся к сервисным и позволяют вносить коррективы в работу сервера. Чтобы удалить непрочитанные сообщения для группы, нужно в запросе MESSAGES::DELETE_UNREAD_MESS вместо TLV(UIN, …) указать TLV(GROUP_ID).

Рисунок 3.6 - Схемы модификации контакт-листа

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

Рисунок 3.7 - Схемы управления работой сервера

На рисунке 3.9 представлены схемы получения информации с сервера, которые обычно выполняются сразу после аутентификации.

Рисунок 3.8 - Схемы управления учетной записью

Рисунок 3.9 - Схемы получения информации с сервера

3.2 Сервер: LIMone-server

Разработанный сервер является последовательным, использует неблокирующие сокеты с функцией select. Данный механизм позволяет отслеживать изменения, происходящие во множестве открытых сокетов, и обрабатывать их последовательно. Сокет, отвечающий за прием запросов на соединение, именуется listener. Каждый из сокетов содержится в закрепленном за ним буфере (TemporaryBuffer), а сами буферы содержатся в списке clients. Для каждого подключившегося клиента сервер выделяет временный буфер (объект класса TemporaryBuffer), который будет хранить часть пакета, полученного от клиента, если пакет не дошел полностью. Этот объект содержит не только указатель на область памяти, куда будет осуществляться считывание, но и сам сокет клиента, которому отведен данный буфер.

struct TemporaryBuffer

{

SOCKET sock; // Сокет, с которого считывается пакет.

uint8_t buf[PACK_MAX_SIZE];// Буфер, содержащий часть пакета.

uint16_t offset; // Отступ внутри буфера от его начала.

TemporaryBuffer()

{

sock = INVALID_SOCKET;

offset = 0;

}

/*

* Разбирает заголовок считываемого пакета.

*/

bool decode_header(HEADER &h)

{

if (buf[0] != HEADER_START) return false;

h.packtype = buf[1];

h.packtype = (h.packtype << 8) | buf[2];

h.seq = buf[3];

h.seq = (h.seq << 8) | buf[4];

h.size = buf[5];

h.size = (h.size << 8) | buf[6];

return true;

}

};

Как только пакет будет считан полностью, он будет переписан в буфер объекта pack (класса Package), а сам временный буфер будет очищен. Для считывания пакета предназначен метод класса Package, именуемый read_package. Данный метод считывает пакет во временный буфер tbuf и возвращает:

- 0, если пакет не дошел полностью,

- минус 1, если соединение разорвано,

- минус 2, если заголовок пакета испорчен,

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

int Package::read_package(TemporaryBuffer &tbuf)

{

int bytes;

if (tbuf.offset < HEADER_OFFSET)

{

bytes = recv(tbuf.sock, (__buf*)(tbuf.buf + tbuf.offset),

HEADER_OFFSET - tbuf.offset, 0);

if (bytes > 0) tbuf.offset += bytes;

}

if (tbuf.offset < HEADER_OFFSET) return 0;

HEADER h;

if (!tbuf.decode_header(h))

{

tbuf.offset = 0;

return -2;

}

bytes = recv(tbuf.sock, (__buf*)(tbuf.buf + tbuf.offset),

h.size - (tbuf.offset - HEADER_OFFSET), 0);

if (bytes > 0) tbuf.offset += bytes;

if (tbuf.offset - HEADER_OFFSET < h.size) return 0;

memcpy(buf, tbuf.buf, tbuf.offset);

tbuf.offset = 0;

offset = HEADER_OFFSET;

length = h.size;

return h.size + HEADER_OFFSET;

}

После того, как пакет будет считан полностью, он поступит на обработку в функцию treat_request, которая выделит тип запроса и запустит соответствующий обработчик для данного типа запроса. К таким обработчикам относятся: treat_authorization, treat_contact_list, treat_general, treat_messages. Каждый из них определяет подтип запроса и запускает соответствующую функцию, реализующую запрошенную операцию.

bool treat_request(SOCKET sock, Package &pack)

{

HEADER head;

if (!pack.decode_header(head)) return false;

if (head.packtype == HEADER_PACKAGE_TYPE::KEEP_ALIVE)

return true;

switch (HEADER_PACKAGE_TYPE::get_category(head.packtype))

{

case HEADER_PACKAGE_TYPE::GENERAL::PREFIX:

return treat_general(sock, pack);

case HEADER_PACKAGE_TYPE::AUTHORIZATION::PREFIX:

return treat_authorization(sock, pack);

case HEADER_PACKAGE_TYPE::CONTACT_LIST::PREFIX:

return treat_contact_list(sock, pack);

case HEADER_PACKAGE_TYPE::MESSAGES::PREFIX:

return treat_messages(sock, pack);

}

return false;

}

Для разбора поступившего от клиента пакета предназначены следующие методы класса Package:

- bool decode_header(HEADER &h) - разбирает заголовок считываемого пакета, записывает его в h и возвращает true в случае успеха, возвращает false если заголовок испорчен;

- uint16_t getPackSeqNumber() - возвращает номер пакета, содержащийся в заголовке;

- bool decode_TLV(const TAG tag, TLV &tlv) - считывает TLV из буфера с требуемым тегом tag и помещает ее в tlv; возвращает true, если TLV найдена и успешно разобрана на составляющие, в противном случае возвращает false.

bool Package::decode_header(HEADER &h)

{

if (buf[0] != HEADER_START) return false;

uint16_t _offset = offset;

offset = 1;

h.packtype = getUIntN<PACKTYPE>();

h.seq = getUIntN<uint16_t>();

h.size = getUIntN<uint16_t>();

offset = _offset;

return true;

}

bool Package::decode_TLV(const TAG tag, TLV &tlv)

{

TAG t;

uint16_t l;

clearOffset();

while ((length + HEADER_OFFSET - offset) >=

(int)sizeof(uint16_t)*2)

{

t = getUIntN<TAG>();

l = getUIntN<uint16_t>();

if (t == tag)

{

if ((length + HEADER_OFFSET - offset) < l)

return false;

tlv.T = t;

tlv.L = l;

tlv.set_V(buf + offset);

return true;

}

else offset += l;

}

return false;

}

После разбора пакета и обработки запроса, сервер высылает ответ, сформированный в виде пакета в соответствии со структурой протокола. Для формирования пакета предназаначены следующие методы класса Package:

- void generate_header(const PACKTYPE packtype[, const uint16_t HEADER_datagram]) - создает заголовок пакета;

- void setPackSeqNumber(uint16_t seqNumber) - устанавливает номер пакета в его заголовок;

- void write_TLV(const TAG T[[, const uint16_t L], V]) - записывает TLV с указанным тегом T.

После того, как пакет сформирован, он отправляется клиенту с помощью метода класса Package, именуемого send_package. Данный метод отправляет пакет получателю sock, с указанием флагов отправки; возвращает количество отправленных байт пакета либо минус 1, если отправить не удалось.

int Package::send_package(SOCKET sock, int flags)

{

int total = 0;

int n = 0;

uint8_t i = 0;

while(total < length + HEADER_OFFSET)

{

n = send(sock, (__buf*)(buf + total),

length + HEADER_OFFSET - total, flags);

if (n == 0) return -1;

if(n < 0)

{

if (i == WAITING) return -1;

else

{

sleep(1);

i++;

continue;

}

}

total += n;

}

return total;

}

После отключения клиента от сервера отведенный ему временный буфер удаляется из списка clients.

Контакт-лист на стороне сервера состоит из групп - экземпляров структуры Group, и контактов - экземпляров структуры Contact, оба - наследники структуры Entity:

struct Entity

{

string Name; // Имя элемента.

GROUP_ID ParentGroupID; // ID группы-родителя.

void *reference;// Указатель на дополнительные данные.

Entity()

{

Name = "";

ParentGroupID = 0;

reference = NULL;

}

};

// Группа.

struct Group : public Entity

{

GROUP_ID GroupID; // ID группы.

Group() { GroupID = 0; }

};

// Сотрудник (контакт).

struct Contact : public Entity

{

string UIN; // Уникальный идентификатор сотрудника.

string Surname; // Фамилия.

string Patronymic; // Отчество.

string Post; // Должность.

string Telephone; // Телефон.

STATUS Status; // Статус.

string StatusText; // Статус-текст.

string Password; // Пароль учетной записи.

SOCKET sock;

Contact()

{

UIN = Surname = Name = Patronymic = Telephone = "";

sock = INVALID_SOCKET;

Status = STATUSES::OFFLINE;

StatusText.clear();

}

};

Контакт-лист представлен в виде двух списков:

// Список групп.

list<Group> group_list;

// Список контактов (сотрудников).

list<Contact> contact_list;

Контакт, соответствующий администратору, именуется root. Запросы, поступающие с этого сокета, обрабатываются в первую очередь.

Пересылаемые текстовые сообщения формируются и хранятся в виде структур Message, а передаваемые файлы - в виде структур File. Обе эти структуры унаследованы от структуры AbstractMessage:

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

struct AbstractMessage

{

string UIN_to; // UIN получателя.

string UIN_from; // UIN отправителя.

string DateTime; // Дата и время отправки в формате

// "dd.mm.yy HH:MM:SS".

/*

* Установка времени отправки.

*/

void set_current_time()

{

char s[20];

time_t ct = time(NULL);

struct tm *lct = localtime(&ct);

strftime(s, 20, "%d.%m.%y %H:%M:%S", lct);

DateTime = string(s);

}

};

// Текстовое сообщение.

struct Message : public AbstractMessage

{

GROUP_ID Group_to; // ID группы-получателя

//(при передаче сообщения группе).

string Text; // Текст сообщения.

bool IsGroupMessage;

void clear()

{

UIN_to = UIN_from = DateTime = Text = "";

Group_to = 0;

IsGroupMessage = false;

}

};

// Передаваемый файл.

struct File : public AbstractMessage

{

FILE_ID FileID; // Идентификатор передаваемого файла.

string FileName; // Имя файла.

FSIZE FileSize; // Размер файла.

bool accepted; // Флаг подтверждения приема.

bool canceled; // Флаг отмены передачи.

bool finished; // Флаг завершения передачи.

void *reference; // Указатель на дополнительные данные.

File()

{

accepted = false;

canceled = false;

finished = false;

FileID = 0;

FileSize = 0;

}

};

Для записи информации о группах, контактах, сообщениях в пакет предназначены следующие методы класса Package:

- void write_group_info(const Group &p);

- bool read_group_info(Group &p);

- void write_base_user_info(const Contact &p);

- void write_user_info_with_status(const Contact &p);

- bool read_base_user_info(Contact &p);

- bool read_user_info_with_status(Contact &p);

- void write_unread_messages(const Message &p);

- bool read_unread_messages(Message &p).

Схема работы сервера представлена на рисунке 3.10.

Размещено на http://www.allbest.ru/

Рисунок 3.10 - Схема работы сервера

Код программы, реализующей данную схему работы, а также обработку поступающих запросов, представлен в приложении Б (исходный код сервера).

3.3 Администрирующий клиент: LIMone-admin

В своей работе этот клиент использует компонент network, который входит в состав Qt Framework. Этот компонент предоставляет класс QTcpSocket, с помощью которого клиент подключается к серверу, высылает и принимает пакеты.

Большинство из модулей администрирующего клиента, а именно: apphelp, connectwidget, contactstree, mainwindow, simpledialogs - предназначены для создания графического интерфейса пользователя. В модуле global_vars описаны глобальные переменные, используемые в нескольких модулях проекта. Работа по протоколу ведется в модуле widget посредством класса Widget. Подключение к серверу выполняется в модуле connectwidget с использованием сокета sock и параметров - used_ip и used_port, описанных в модуле global_vars. После того, как пользователь нажмет кнопку «Аутентификация», будет запущен слот, реализующий подключение к серверу:

void ConnectWidget::slot_pref()

{

used_address = serv_ip->text();

used_port = serv_port->value();

pb->reset();

bt->setCurrentWidget(pb);

sock->disconnectFromHost();

sock->connectToHost(used_address, used_port);

}

Если соединение с сервером будет успешно установлено, то будет выслан сигнал connected(), который вызовет процедуру аутентификации, именуемую slot_login(string pass), где pass - пароль администратора.

void Widget::slot_login(string pass)

{

HEADER h;

TLV tlv;

int cnt, bytes_read;

while (sock->bytesAvailable() > 0 ||

sock->waitForReadyRead())

{

bytes_read = read_from_server(inpack);

if (bytes_read < 0) return;

if (bytes_read > 0) break;

}

if (bytes_read == 0)

{

disconnect_form_server();

return;

}

if (!inpack.decode_header(h))

{

disconnect_form_server();

return;

}

if (h.packtype != HEADER_PACKAGE_TYPE::GENERAL::

SERVER_PUBLIC_KEY)

{

disconnect_form_server();

return;

}

if (!inpack.decode_TLV(TLVS::PUBLIC_KEY, tlv))

{

disconnect_form_server();

return;

}

ByteQueue queue;

StringSource str_key(tlv.getString(), true /*pumpAll*/);

str_key.TransferTo(queue);

queue.MessageEnd();

try

{

serverPublicKey->Load(queue);

}

catch (BERDecodeErr e)

{

disconnect_form_server();

return;

}

if(!serverPublicKey->Validate(rng, 3))

{

disconnect_form_server();

return;

}

string cipher;

RSAES_OAEP_SHA_Encryptor e(*serverPublicKey);

StringSource(pass, true, new PK_EncryptorFilter(rng, e,

new

StringSink(cipher)));

outpack.clear();

outpack.write_TLV(TLVS::PASSWORD, cipher);

outpack.generate_header(HEADER_PACKAGE_TYPE::GENERAL::

ROOT_AUTHORIZATION);

cnt = send_to_server(outpack,

"Ключ не может быть отправлен!");

if (cnt < 0) return;

bytes_read = 0;

while (sock->bytesAvailable() > 0 ||

sock->waitForReadyRead())

{

bytes_read = read_from_server(inpack);

if (bytes_read < 0) return;

if (bytes_read > 0) break;

}

if (bytes_read == 0)

{

disconnect_form_server();

return;

}

if (!inpack.decode_header(h))

{

disconnect_form_server();

return;

}

if (h.packtype != HEADER_PACKAGE_TYPE::GENERAL::

ROOT_AUTHORIZATION)

return;

if (!inpack.decode_TLV(TLVS::OK, tlv))

{

disconnect_form_server();

if (inpack.decode_TLV(TLVS::ERRORS, tlv))

QMessageBox::critical(this, trUtf8("Авторизация

администратора"),

QString::fromStdString(

tlv.getString()));

else QMessageBox::critical(this,

trUtf8("Авторизация администратора"),

trUtf8("Не обнаружены поля OK|ERR"));

return;

}

}

Для считывания пакетов с сервера служит метод read_from_server. Как и в случае с сервером, считывание пакета изначально производится во временный буфер temp_buf, который является объектом класса TemporaryBuffer. Если пакет дошел полностью, то будет переписан в pack, и метод вернет его размер:

int Widget::read_from_server(Package &pack)

// пытаемся считать ответ сервера (пакет)

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

// 0 - пакет не дошел полностью

// в случае неудачи выдает ошибку err и возвращает -1

{

if (!sock->isOpen())

{

temp_buf.offset = 0;

disconnect_form_server();

QMessageBox::critical(this, trUtf8("Ошибка"),

trUtf8("Соединение не установлено!"));

return -1;

}

int bytes;

if (temp_buf.offset < HEADER_OFFSET)

{

bytes = sock->read((char*)(temp_buf.buf +

temp_buf.offset),

HEADER_OFFSET - temp_buf.offset);

if (bytes > 0) temp_buf.offset += bytes;

}

if (temp_buf.offset < HEADER_OFFSET) return 0;

HEADER h;

if (!temp_buf.decode_header(h))

{

temp_buf.offset = 0;

disconnect_form_server();

QMessageBox::critical(this, trUtf8("Ошибка"),

trUtf8("Заголовок пакета испорчен!"));

return -1;

}

bytes = sock->read((char*)(temp_buf.buf + temp_buf.offset),

h.size - (temp_buf.offset - HEADER_OFFSET));

if (bytes > 0) temp_buf.offset += bytes;

if (temp_buf.offset - HEADER_OFFSET < h.size) return 0;

pack.clear();

memcpy(pack.buffer(), temp_buf.buf, temp_buf.offset);

temp_buf.offset = 0;

pack.setLength(h.size);

writeToHistory(pack, true);

return h.size + HEADER_OFFSET;

}

Для отправки сформированного пакета на сервер используется метод send_to_server:

int Widget::send_to_server(Package &pack, string err)

// отправляем пакет размером offset серверу

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

// в случае неудачи выдает ошибку err и возвращает -1

{

if (!sock->isOpen()) return -1;

int cnt;

if ((cnt = sock->write(pack.buffer(),

pack.getPackLength())) != pack.getPackLength())

{

disconnect_form_server();

if (!err.empty())

QMessageBox::critical(this, trUtf8("Ошибка"),

trUtf8(err.c_str()));

return -1;

}

writeToHistory(pack, false);

return cnt;

}

Разбором пакета занимается метод parsePack, который выделяет тип и подтип пакета, после чего выполняет соответствующие назначению пакета действия:

void Widget::parsePack(Package &inpack)

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

{

HEADER h;

if (!inpack.decode_header(h)) return;

switch (h.packtype)

{

case HEADER_PACKAGE_TYPE::CONTACT_LIST::GET_GROUP_LIST: …

case HEADER_PACKAGE_TYPE::CONTACT_LIST::GET_CONTACT_LIST: …

case HEADER_PACKAGE_TYPE::AUTHORIZATION::CHANGE_USER_STATUS:…

case HEADER_PACKAGE_TYPE::AUTHORIZATION::CHANGE_USER_INFO: …

case HEADER_PACKAGE_TYPE::CONTACT_LIST::CREATE_USER: …

case HEADER_PACKAGE_TYPE::CONTACT_LIST::CREATE_GROUP: …

}

}

Метод getNeededPack осуществляет считывание и обработку пакетов в ожидании требуемого. Этот метод необходим в том случае, когда для успешного завершения операции (например, создания группы) необходим ответ сервера на отправленный запрос. Данный метод обрабатывает все полученные пакеты пока не получит пакет-ответ на высланный запрос, при этом вернет true; либо пока не закончатся все пакеты, а требуемый так и не будет найден - в таком случае метод вернет false.

bool Widget::getNeededPack(PACKTYPE packtype, Package &pack)

{

int bytes_read = 0;

HEADER h;

while (sock->bytesAvailable() > 0 ||

sock->waitForReadyRead())

{

bytes_read = read_from_server(pack);

if (bytes_read < HEADER_OFFSET) continue;

if (!pack.decode_header(h)) return false;

if (h.seq != 0 && h.packtype == packtype) return true;

else parsePack(pack);

}

QMessageBox::critical(this, trUtf8("Ошибка"),

trUtf8("Сервер не отвечает!"));

return false;

}

Работу по протоколу обеспечивают следующие слоты, которые вызываются нажатием соответствующих кнопок на панели инструментов программы:


Подобные документы

  • Создание клиент-серверного приложения "Чат" с помощью среды визуальной разработки приложений Borland C++ Builder версии 6. Описание функциональности приложения: наличие клиент-серверной архитектуры, обмен короткими сообщениями, а также передача файлов.

    курсовая работа [302,0 K], добавлен 30.01.2012

  • Изучение истории достижений корпорации Oracle. Разработка клиент-серверного приложения на языке Delphi XE, реализующего возможность управления персоналом на предприятии. Основные структуры данных. Создание инструкции работы с приложением "Отдел кадров".

    дипломная работа [974,7 K], добавлен 08.06.2013

  • Сетевое программное обеспечение: общее понятие, содержание, функции. Этапы развития теории компьютерных сетей. Проектирование в среде программирования Borland Builder C++ клиент серверного приложения с использованием сокетов, листинг данной программы.

    курсовая работа [191,5 K], добавлен 07.01.2015

  • Многоуровневые архитектуры клиент–сервер. Диаграммы классов, реализующих уровни презентации, бизнес–логики и базы данных приложения. Словесное описание процесса выполнения транзакций. Создание, изменение и удаление хранимых процедур, их выполнение.

    курсовая работа [3,4 M], добавлен 23.03.2013

  • Разработка компьютерной сети. Спецификация и расчет себестоимости спроектированной сети. Выбор инструментальных средств для реализации разрабатываемого клиент-серверного приложения. Описание логической структуры программного продукта, основные алгоритмы.

    курсовая работа [942,1 K], добавлен 19.03.2012

  • Разработка конфигурации службы. Исследование вычислительной эффективности алгоритма оптимизации. Программная реализация клиент-серверного приложения. Алгоритм решения непрерывной задачи загрузки рюкзака. Подключение веб-сервиса к клиентскому приложению.

    курсовая работа [1,4 M], добавлен 21.01.2017

  • Разработка клиент-серверного приложения, позволяющего взаимодействовать друг с другом с использованием доступа к базам данных. Проектирование связи сервера с базой данных с помощью технологии ODBC. Разработка интерфейса программы, ее тестирование.

    курсовая работа [352,0 K], добавлен 24.08.2016

  • Основные концепции разработки приложения в трёхуровневой архитектуре. Проектное решение, реализующее модель реляционной БД. Спецификация на разработку интерфейса. Описание выполнения транзакций прибытия и убытия судна. Инсталляционные файлы приложения.

    курсовая работа [4,0 M], добавлен 26.12.2011

  • Создание клиент-серверного приложения на основе технологии CORBA. Проектирование многоуровневой системы, в которой клиент при помощи банкомата выполняет необходимые операции. Способы реализации серверов в разных каналах для ускорения обработки данных.

    лабораторная работа [1,1 M], добавлен 08.06.2009

  • Характеристика разновидностей программной реализации чатов. Разработка программы клиент-серверного чата с возможность общения в локальной сети нескольких человек одновременно. Протокол взаимодействия клиента и сервера. Порядок работы с программой.

    курсовая работа [530,7 K], добавлен 25.04.2015

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.