Дипломная работа
РАЗРАБОТКА ПРОГРАММНОГООБЕСПЕЧЕНИЯ ДЛЯ ОЦЕНКИ УРОВНЯ ЗНАНИЙ СТУДЕНТОВ С ПРИМЕНЕНИЕМ ТЕХНОЛОГИИ«КЛИЕНТ-СЕРВЕР»
Москва 2010
/>/>Введение
В настоящее время сфера образованиястала одним из объектов внедрения вычислительной техники и информационныхтехнологий.
ГОУ СПО«Тульский экономический колледж», является одним из среднеспециальных учебныхзаведений Тульской области.
Ввычислительном центре ГОУ СПО «Тульский экономический колледж» имеются 117компьютеров класса Pentium III и выше. Все они расположены в 7 учебных лабораториях.Также имеются необходимые периферийные устройства: струйный принтер HewlettPackard Color Jet 100plus – формат А1, несколько лазерных принтеров; накопители наоптических и гибких дисках, DVD-RW. Все ПК оснащены мультимедийными устройствами(звуковые карты, приводы CD-ROM).
Компьютерыобъединены в локальную сеть по средствам топологии «звезда» под управлением ОС Microsoft Windows 98/XP/Server2003.
Согласнотребованиям современной педагогики, контроль успеваемости предполагаетсяосуществлять в виде тестирования.
Тестированиеможно проводить в виде опросных листов, что требует большой подготовки состороны преподавателя. Наиболее трудоемким моментом является обработкарезультатов тестирования.
Темой данного дипломного проекта является «Разработка программногообеспечения для оценки уровня знаний студентов с применением технологии«Клиент-сервер».
/>/>1.Описание объекта автоматизации
В свободноеот основной работы время, я занимаюсь преподавательской деятельностью на очномотделении ГОУ СПО «Тульский экономический колледж». Данный вид деятельностиразрешен Законом о Государственной гражданской службе РФ.
Система управления колледжа традиционнадля среднеспециального учебного заведения РФ.
Имеются следующие функциональныеподсистемы:
- Директор;
- учебнаячасть: для организации учебного процесса, создания учебных планов, методическихпособий, раздаточных материалов, ведение корреспонденции;
- отделкадров: подготовка письменных документов таких как: приказы, справки, выписки,письма;
- вычислительный центр: проведениелабораторных и практических работ по получению первичных навыков работы накомпьютере и профессиональных навыков по специальности, выполнение расчетов попрактическим работам общеобразовательным и специальным дисциплинам, проверказнаний и умений учащихся (тестирование), проведение внеклассных мероприятий(занятий кружка, олимпиады).
Вычислительная техника в системеуправления ГОУ СПО «Тульский экономический колледж» позволяет автоматизироватьследующие функции управления:
- организацияучебного процесса;
- ведениебухгалтерского учёта;
- ведениедокументации;
- ведениекорреспонденции;
- учебныйпроцесс.
Семь лабораторийвычислительного центра колледжа имеют по пятнадцать персональных компьютеров отIntel Celeron 533 Mhz до Intel Pentium IV 3000 Mhz каждый из нихоснащен системой фильтрации от высокочастотных помех в цепи питания,накопителями FDD, устройствами ввода информации служат: клавиатуры и мыши.Также каждый из компьютеров подключен к сетевому принтеру в лаборатории.
Компьютерыобъединены в сеть по средствам топологии «звезда» через коммутаторы (SWICH) фирмы D-Link.
Вычислительныйцентр обслуживается 4 лаборантами, которые закреплены за определёнными учебнымилабораториями ВЦ. Они подчиняются зав. лабораторией и начальникувычислительного центра.
/>/>2.Постановка задачи/>/> 2.1 Сущность задачи
Одним изважнейших структурных подразделений колледжа является вычислительный центр.Именно там проходят занятия учеников с использованием современныхпедагогических технологий, которые базируются на использовании ПК и программныхсредств.
Одним изэтапов урока является проверка знаний и умений учащихся.
Согласнотребованиям современной педагогики, контроль успеваемости предполагаетсяосуществлять в виде тестирования.
Тестированиеможно проводить в виде опросных листов, что требует большой подготовки состороны преподавателя. Наиболее трудоемким моментом является обработкарезультатов тестирования.
Целью данногодипломного проекта является «Разработка программного обеспечения для оценкиуровня знаний студентов с применением технологии «Клиент-сервер».
Актуальностьпоставленной задачи обусловлена облегчением труда преподавателя связанного спроведением тестирования и обработкой результатов данного тестирования.
Проведяисследование рынка программных продуктов по проведению сетевого тестирования,были выявлены ряд недостатков, в число которых входят:
– высокаястоимость отдельных программных продуктов
– невозможностьработы с математическими формулами
– сложныйдля понимания пользовательский интерфейс
– большаязагрузка ЛВС в момент проведения тестирования
Всевышеперечисленные недостатки послужили поводом для разработки собственногопрограммного продукта.
Назначение программы – проведениецентрализованных итоговых занятий по разным дисциплинам в виде интерактивноготестирования.
Основными задачами дипломногопроекта являются:
– разработка клиентской частисистемы тестирования
– разработка серверной частисистемы тестирования
– разработка системыотчетности по результатам тестирования
Функционирование автоматизированнойсистемы тестирования, далее АСТ, начинается с создания для каждой дисциплиныотдельной базы данных, содержащей вопросы теста, далее формируется «Тестпакет», содержащий всю информацию необходимую для осуществления тестирования судаленной станции. В процессе тестирования появление вопросов происходит вслучайном порядке. Возможности разработанного сетевого протокола позволяютвести двустороннее общение между преподавателем и студентом. Также программапозволяет осуществлять контроль, за ходом тестирования. Так в любой моментпосле начала тестирования преподаватель может посмотреть результатытестирования каждого ученика (количество вопросов, на сколько из них были даныправильные ответы и сколько допущено ошибок), приостановить или прекратитьтестирование, а также исключить отдельного ученика из процесса тестированияотключив его от сервера.
Выходной информацией АСТ являетсяотчет успеваемости.
Периодичность примененияавтоматизированной системы зависит от плана преподавателя по проведениютестирования.
Для комфортной работы с программойнеобходим компьютер ниже перечисленной конфигурации:
- сетеваяплата от 10 Мб/с и выше;
- процессортактовой частотой не ниже 300 Мгц;
- оперативнаяпамять не менее 64 Мб;
- объемжесткого диска не менее 1 Гб;
- монитор 15 дюймов;
- разрешениемонитора 1024x768 при 16 битной цветовой палитре;
/>/>3.Описание логической структуры
Система представляет собойсовокупность двух подпрограмм осуществляющих проведения тестирования в рамкахлюбой сети поддерживающей протокол TCP-IP.
Подпрограмма «Тест-Сервер»позволяет осуществлять управление над ходом тестирования студентов, онаобъединяет в себе возможности сетевого сервера, приложения и СУБД тестирования.
Подпрограмма «Тест-Клиент» позволяет осуществлять тестирование конкретногоученика, рабочая станция которого подключена к «Тест-Серверу» по заранееспроектированной схеме, способной динамически изменяться в ходе тестирования всоответствии с требованиями преподавателя.
Общая схема взаимодействия серверной и клиентской части системыприведена на рисунке 1.
/>
Рис. 1. Общая схемавзаимодействия серверной и клиентской части системы
Общая схемавзаимодействия отдельный частей системы приведена на рисунке 2.
/>
Рис 2. Общаясхема взаимодействия отдельный частей системы/>/>3.1 Описание организацииданных/>/> 3.1.1 Описание входной ивыходной информации
Входной информацией является: Список вопросов, образующих билет икритерий оценки. Совокупность этих данных образуют промежуточное звено процессатестирования – База Теста. Для обеспечения возможности сетевого тестированиянеобходима еще одна деталь – IP адрес станции, с которой будет осуществлятьсяуправление ходом тестирования, то есть станции, которая будет обозначена какведущая и где будет развернут Тест-Сервер. Ввод информации необходимой дляформирования Базы Теста осуществляется в главной форме подпрограммы Тест-Серверна вкладке База вопросов.
База Тестапредставляет собой каталог, имеющий имя преподавателя по чьему предметуосуществляется тестирование. В данном каталоге располагаются файлы настроек дляданной базы теста, а именно – файл QuestKey.ini – содержит номера правильныхответов для каждого вопроса; файл WorkSet.ini – содержит служебную информациюдля данной базы теста, такую как: количество вопросов в тесте, ограничениевремени для прохождения теста, формат изображений файлов вопросов теста.Основной каталог базы теста содержит N (зависящее от количества вопросов в тесте)дочерних каталогов имеющих системное имя в виде чисел от 1 до N, в которых содержатсяизображения вопроса и вариантов ответов. Количество изображений может бытьпеременным (для осуществления случайного выбора вопроса теста), но должно бытьне менее 1.
/>
Рис. 3Формирование базы теста
Каждоеизображение вопросов и вариантов ответов должно иметь системное имя в видесквозной нумерации от 1 до номера последнего вопроса. (например если всего 100файлов вопросов, нумерация должна быть от 1 до 100). Все изображения должныиметь одинаковый формат, например, если некоторое количество файлов сделаны в формате JPEG Image file, то и все последующиедолжны быть в этом формате.
Структуракаталогов базы теста приведена на рисунке 4.
Дляклиентской части системы единственным файлом настроек является файл ip.dat, который содержит IP-адрес сервератестирования
/>
Рис. 4Структура каталога базы теста
Основнымэлементом выходной информации является отчет успеваемости, имеющем следующиеполя:
- Ф.И.О. студента;
- группа;
- общее количествовопросов;
- количество правильныхответов;
- количество не правильныхответов;
- оценка;
- время прохождения теста.
Предварительныйпросмотр отчета можно произвести из формы Отчет успеваемости, а также сохранитьв файл и вывести на печать.3.1.2Система классификации и кодирования
Дляэффективного обмена информацией между автоматизированными системами управленияразличных уровней требуется создание единого информационного обеспечения,включающего систему классификации и кодирования технико-экономическойинформации.
Системаклассификации и кодирования технико-экономической информации представляет собойкомплекс взаимосвязанных общесоюзных классификаторов, а также комплекснормативно-технических и методических материалов, характеризующих систему.
Основные работы по созданию системыклассификации и кодирования технико-экономической информации выполняетГосстандарт.
Классификаторыпо их применению делятся на категории:
– общегосударственные;
– отраслевые;
– классификаторыпредприятия.
Общегосударственные– утверждаются ГОСТами и РОСТами и обязательны к применению во всех отраслях государства.
Отраслевые – разрабатываются дляспецифических видов информации, циркулирующей внутри отрасли и утверждаютсяминистерствами и ведомствами. Обязательны к применению только в данной отрасли.
Классификаторыпредприятия – аналогичны отраслевым, создаются и обязательны к применению наотдельных предприятиях.
В подсистеме «Учебная часть»используются следующие классификаторы:
1. Отраслевойклассификатор для кодирования кода группы:
ХХХX – XХ
код названия специальности
код годапоступления
код (флаг) некоммерческой группы
код текущего курса обучения
код (флаг) базы поступления
Пример: 0414-ФК – База 11 классов, четвертыйкурс, некоммерческая группа, последняя цифра года поступления, кодспециальности.
3.1.3Защита и сохранность данных
Постоянное развитие компьютернойинфраструктуры, усложнение компьютерных систем, создание сетей, увеличениеобъема хранимой и передаваемой информации порождает ряд серьезных проблем,связанных с целостностью и сохранностью данных. Для обеспечения сохранностиинформации выделяют следующий комплекс мер:
- дублированиеинформации в виде резервных копий на том или ином носителе;
- защитаот случайного удаления файлов;
- защитаот несанкционированного доступа;
- защитаот компьютерных вирусов;
- архивныекопии;
- программный«уход» за жесткими дисками.
Для зашиты отнесанкционированного доступа применяют различные методы защиты: процедурные,аппаратные, программные или комбинированные.
Процедурные методы обеспечивают доступ к данным только темпользователям, которые имеют соответствующее разрешение.
Программныеметоды защиты очень разнообразны:
- использованиеключевых меток на машинном носителе;
- использованиесерийных номеров программ;
- использованиеспециального кода на инсталляционных дискетах.
Комбинированные методы защитыобъединяют различные методы: процедурные и программные, аппаратные ипрограммные и т.д.
Резервное копирование – этопостоянное создание резервных копий рабочей информации. Существует многопрограмм предназначенных для создания резервных копий. Из них наиболее частоиспользуются Norton Backup и другие программы Backup из разных программныхпакетов или Утилит, а также программа-архиватор WinRAR.
Так в программе «Оценка уровня знаний студентов с применением технологии «клиент-сервер» из пунктаглавного меню Файл \ Резервное сохранение можно создать резервную копию базы теста.Кроме этого дистрибутив программы, созданный с помощью специальной надстройки«InstallerXP», имеет несколько резервных копий на жестком диске рабочего местаи на оптических дисках при главном компьютере ВЦ.
Чтобы информация, записанная на CDи RW дисках, сохранилась дольше, необходимо соблюдать определенные правила итребования: диски следует хранить в специальных коробках, упаковках илифутлярах, предназначенных для этого, во избежание попадания пыли, физическихповреждений, солнечных лучей.
Кроме создания резервных копий, дляпредотвращения потери информации на жестком или гибком диске, следует проводитьобслуживание дисков: проводить полную проверку, то есть проверять на наличиефизических ошибок, проверять структуру файлов и каталогов; если возникаютошибки, то исправлять их; производить дефрагментацию; удалять ненужнуюинформацию. Обслуживание необходимо проводить регулярно. Для этого можно использоватьследующие программные средства (утилиты) как Norton Disk Doctor (проверкажесткого диска), Norton Speed Disk (дефрагментация диска) из пакета NortonUtilities, Fix-It Utilities или Scandisk, который содержится в самой ОСWindows.
Частоинформация теряется или повреждается в результате действий компьютерныхвирусов.
Компьютерныйвирус – это фрагмент программного кода, который размножается, копируя себя втело других программ, при этом замедляется работа компьютера или полностью(либо частично) разрушается файловая система. Для того чтобы вирус не поразилкомпьютер необходимо: ограничить к нему доступ посторонних лиц, использующихразличные носители информации; проверять на наличие вируса, если же онобнаруживается, то необходимо использовать антивирусные программы (NortonAntivirus, Antiviral Toolkit Pro, Dr. Web и др.). Антивирусные программы – этопрограммы, написанные специально для выявления и уничтожения вирусов.
Еще одинметод защиты программ от заражения вирусами – архивация данных.
Если наличиевируса очевидно (замедление работы жесткого диска, уменьшение скоростивычислительного процесса, появление несоответствующих данной задаче сообщенийили картинок, внезапная потеря данных), то следует запустить антивируснуюпрограмму. Если она нашла вирус и излечила компьютер от него, то потеряинформации будет минимальной или вообще ее может не быть. Если же не удалосьвовремя излечить систему от вируса и после его действий почти вся информациябыла потеряна, то целесообразно произвести форматирование жесткого диска, чтобыполностью избавиться от файлов, зараженных вирусом. Затем загрузить систему ссистемной дискеты или компакт диска и перенести на жесткий диск информациюрезервных копий.
Иногдатребуется восстановить случайно уничтоженный файл. Для этого можно использоватьпрограмму UnErase из программного пакета Norton Utilities либо OnTrack Easy Recovery.3.1.4Организация и ведение информационной базы
Формирование базы тестаосуществляется каждой дисциплины, ответственность за выполнение подготовкивходной информация возлагается на преподавателя. По окончании подготовкиоперативной информации необходимо ввести информацию в базу теста и сохранитьготовую базу в автономный каталог с названием дисциплины и именем преподавателя.
С целью поддержания баз тестов вактуальном состоянии необходимо организовывать периодическое редактированиевопросов тестов в соответствии с требованиями учебного плана, ответственностьза выполнение этой работы также возлагается на преподавателя.
Информация хранится в каталоге Questions,далее каталог «База Теста» и IP-адрес в файле IP.dat соответственно.
В каталоге База Теста содержатсявопросы теста варианты ответов на каждый вопрос, номер правильного ответа ипорядковый номер вопроса. В форме осуществляющей ввод и редактированиеинформации Базы Теста предусмотрены активные кнопки и сопроводительныесообщения, которые позволяют улучшить эргономичность и избавиться отдополнительных элементов интерфейса. Для повышения производительности выборверного ответа на вопрос осуществляется визуально, т.е. щелчком мыши направильном ответе. В таблице IP-адрес содержится постоянная информациянеобходимая для осуществления сетевого подключения и функционирования всейсетевой подсистемы программы.
Массивы выходной информации послерешения задачи сохраняются в файл. При необходимости сохранения информации, делаетсяпоименованная копия этой информации на любом доступном носителе. Срок хранениявыходной информации определяется преподавателем.
Для связи выходной информации сдругими задачами используется метод DDE – Dynamic Data Exchange, те обнуление,не требующихся для дальнейшего функционирования системы или принятияуправленческого решения, данных и освобождение, таким образом, ресурсовпроисходит автоматически.
/>/>4.Описание программно-технических средств/> 4.1Программно-технические средства, необходимые для разработки программы
Дляразработки автоматизированной системы была выбрана платформа WINTEL подуправлением операционной системы Windows XP SP2.
В качествесреды программирования для решения поставленной задачи была выбрана BorlandDelphi 6.0 Enterprise.
Delphi –инструмент для создания приложений и систем, функционирующих на платформеWindows. В основе нее лежит объектно-ориентированный язык высокого уровняObject Pascal, разработанный профессором Высшего технического училища (г. Цюрих,Швейцария) Никлаусом Виртом.
Основнымипринципами ООП:
– инкапсуляцияпредставляет собой объединение данных и обрабатывающих их методов(подпрограмм) внутри класса. Это означает, что в классе инкапсулируются(объединяются и помещаются внутри класса) поля, свойства и методы. При этомкласс приобретает определенную функциональность;
– наследованиезаключается в порождении новых объектов-потомков от существующих объектовродителей, при этом потомок берет от родителя все его поля, свойства и методы.В дальнейшем наследуемые поля, свойства и методы можно использовать внеизменном виде или переопределять (модифицировать). В новый объект добавляютсяновые элементы, определяющие его особенность и функциональность. Удалитькакие-либо элементы родителя в потомке нельзя. В свою очередь, от новогообъекта можно породить следующий объект, в результате образуется деревообъектов, или иерархия классов. В начале этого дерева находится базовый классTObject, который реализует элементы, наиболее общие для всех объектов,например, действия по созданию и удалению объектов. Чем дальше тот или инойобъект находится в дереве от базового класса, тем он более специфичен.
– полиморфизмзаключается в том, что методы различных объектов могут иметь одинаковыеимена, но различное содержание. Это достигается переопределением родительскогометода в классе-потомке. В результате родитель и потомок ведут себя по-разному.При этом обращение к одноименным методам различных объектов выполняетсяаналогично.
Следованиестандартам индустрии и открытость к взаимодействию с любыми частными решениямигарантирует успех проектов, разрабатываемых с использованием Delphi.
Delphiустанавливает стандарт для сред разработки приложений Windows. Delphiобеспечивает набор возможностей специально ориентированных на многократноеиспользование компонентов. Многие аспекты работы Delphi можно настраивать.Созданные полезные объекты – компоненты и шаблоны приложений и форм будутдоступны для будущих разработок.
Delphiявляется первой системой RAD, в которой удачно соединились средства визуальногопроектирования и оптимизирующий компилятор, чего, к сожалению, нельзя сказать одругих системах RAD. Delphi является единственным полноценным средством промышленнойразработки систем клиент-сервер, на которой основывается и даннаяавтоматизированная система контроля знаний.
В составDelphi входит обширная библиотека компонентов, с помощью которой можно избежатьручного написания программ. С другой стороны, в любой момент можно прибегнуть книзкоуровневым ассемблерным процедурам. Можно создавать приложения в визуальномрежиме. Работая в Delphi, можно с помощью нажатия одной клавиши создатьисполняемый файл в формате EXE, однако, при необходимости, можно компилироватьи файлы DLL, драйверов устройств, а также консольных приложений.
Существуетмножество достоинств, благодаря которым можно выделить Delphi из ряда другихсредств разработки:
- обширная библиотекаклассов;
- быстрый оптимизирующийкомпилятор, генерирующий машинный код;
- встроенный отладчик,равных которому нет;
- простой в освоениимеханизм доступа к базам данных;
- мощная и удобная в работесреда разработки.
- возможности Delphi,которые делают ее такой гибкой:
- прямой доступ кпрограммному интерфейсу Windows;
- встроенный ассемблер иподдержка программирования в машинных кодах;
- возможность созданияпользовательских компонентов VCL и ActiveX;
- поддержка формата DLL идругих выполняемых файлов Windows;
- возможностьмногоуровневой разработки приложений;
- полная объективнаяориентированность – в программах можно создавать объекты, берущие начало как отбиблиотечных классов, так и от созданных программистом.
Delphiпредоставляет прямой доступ ко многим типам локальных и удаленных серверов базданных. Также предоставляет множество различных типов для хранения целых,вещественных (с плавающей запятой), логических (boolean), символьных (char),строковых значений, а также указателей. Помимо этого имеются типы, определяемыепользователем: множества (sets), записи (records) и объектные переменные.Поскольку имеется столько разнообразных типов, понимание чужого программногокода может быть затруднено, если будут встречаться маловразумительные именапеременных.
Часто дляобеспечения взаимодействия различных приложений или частей одного приложенияорганизуется обмен данными. Для этого предоставляются следующие средства:
– использованиебуфера обмена;
– динамическийобмен данными.
Буфер обменапредставляет собой область оперативной памяти и специальных функций, которыеиспользуются для временного хранения файла. Буфер обмена является общим длявсех программ, любое приложение может помещать в него информацию и считыватьего оттуда. Буфер обмена способен хранить данные самых разных типов и содержитсведения об их формате. Буфер обмена обеспечивает простейший статический способобмена данных между приложениями. Данные в общей области обмена обновляются иявляются динамическими. Однако термин статический понимается в том смысле, чтокаждый раз, когда приложение или пользователь хочет получить новые данные избуфера обмена или поместить их туда, они должны выполнять для этогосоответствующие операции.
Длявыполнения операций обмена данными через буфер в Delphi предназначенспециальный класс TClipBoard.
С помощьюсвойств и методов объекта Clipboard при работе с буфером обмена можно выполнитьстандартные операции, например, очистить буфер или проанализировать типхранимых данных. Для доступа к объекту буфера обмена в разделе Uses модуля, вкотором выполняются операции с объектом буфера, указывается модуль Clipboard.
В Delphiсоздана поддержка технологии DDE (Dynamic Data Exchange – динамический обменданными).
Динамическийобмен данными (Dynamic Data Exchange – DDE) представляет собой технологию,которая связана с передачей данными между приложениями, работающими подуправлением операционной системы Windows. С помощью технологии DDE дваприложения могут динамически взаимодействовать и обмениваться текстовымиданными во время их выполнения. При этом изменения в одном приложениинемедленно отражаются во втором приложении. Кроме того, с помощью технологииDDE можно из одного приложения управлять другим приложением, например,Microsoft Word или Excel.
Придинамическом обмене два приложения соблюдают соглашение об обмене иустанавливают между собой непосредственную связь на время передачи данных. Приэтом программа, запрашивающая данные, становится клиентом, а программа,служащая источником данных, является сервером. В зависимости от направленияпередачи данных одно и то же приложение может одновременно быть и клиентом исервером. Организация динамического обмена данными включает в себя дваследующих этапа:
· установкасвязи между клиентом и сервером. Ее можно устанавливать при разработке и привыполнении приложения;
· передачатекстовых данных, при этом возможны следующие действия:
– получениеданных от сервера;
– передачаданных на сервер;
– посылкасерверу команд.
Delphiпозволяет создавать оба типа приложений – сервера и клиента, при этом каждое изних создается отдельно. Для создания приложений, участвующих в динамическомобмене данными, существуют соответствующие компоненты. Для совместной отладкидвух приложений можно сначала создавать сервер, а затем – клиент.
Вкачестве дополнительных средств, применяемых при реализации проекта можноотметить такие как Macromedia Flash MX – c помощью этого средства были созданы элементы анимациидля некоторых процессов, растровый графический редактор Adobe Photoshop CS2 – его возможности помогли реализовать в проекте всенеподвижные графические элементы.
Вседанные приложения использовались в режиме TRIAL 30-дневнойтестовой версии.
Аппаратнаячасть разработки проекта с учетом инструментальных средств предусматриваетиспользование ПК следующей конфигурации:
– процессортактовой частотой не ниже 700 Мгц;
– объемоперативной памяти не менее 128 Мб;
– диагональмонитора 15 и более дюймов;
– объемвидеопамяти от 32 Мб;
– разрешениемонитора 1024x768 при 16 битной палитре;
– объемжесткого диска не менее 2,1 Гб (1,5 Гб. – ОС Windows + 600 Mb – Borland Delphi 6.0)./>4.2 Программно-технические средства, необходимые дляэксплуатации программы
Автоматизированнойсистемы контроля знаний на основе архитектуры клиент-сервер работает в сетевомрежиме. Для эксплуатации программы необходимы следующие программные средства:
Сервернаячасть:
- операционная системаWindows 98 SE /Me/XP/2000/2003;
- пакет программ Microsoft Office XP (и последующие версии)для вывода отчетности.
- присутствие следующихкомпонентов операционной системы:
· сетеваяплата либо контроллер удаленного доступа;
· протоколTCP/IP;
Клиентскаячасть:
- операционная системаWindows 98 SE /Me/XP/2000/2003;
- присутствие следующихкомпонентов операционной системы:
· сетеваяплата либо контроллер удаленного доступа;
· протоколTCP/IP;
Основныехарактеристики ОС Windows XP:
– многозадачность(одновременно может работать несколько приложений);
– работас сетью ОС (на уровне ядра системы организован клиент / сервер сети);
– изоляцияпроцессов (если во время работы какое-либо приложение совершило сбой, и врезультате было закрыто аварийно, то это не сказывается на работе другихприложений и процессов системы);
– поддержкаогромного количества оборудования (в том числе, устаревшего и современного)всех известных производителей;
– широкиевозможности настройки многих узлов системы (графических, интерфейсных, сетевых ит.д.);
– обширнаясправочная система по многим узлам операционной системы.
ИспользованиеАвтоматизированной системы контроля знаний предусматривает следующие требованияк аппаратным средствам:
- сетевая плата от 10 Мб/с;
- сетевая среда (физическийуровень);
- процессор тактовойчастотой не ниже 500 Мгц;
- оперативная память неменее 64 Мб;
- объем жесткого диска неменее 2 Гб;
- монитор 15 дюймов;
- разрешение монитора1024x768 при 16 битной палитре;/>4.3 Тестирование программы
Длятестирования отдельных модулей-подпрограмм и автоматизированной системы в целомна ряду со стандартными интегрированными средствами тестирования и отладки,предоставляемые разработки Borland Delphi 6.0. (build 5.62) – IntegratedDebugger, были применены и дополнительные средства, такие как BorlandWinSight, Spy32 for Windows9x/NT, NuMega BoundsChecker, Registry MonitorSysinternals Corp.
Дляосуществления отладки при помощи Integrated Debugger необходимо активироватьэту систему, с этой целью на странице Debugger Options пункта меню Tools среды Delphi был установлен флаг Integrated Debugging.
Реализация итестирование отдельных модулей происходила в следующем порядке:
- разработкаалгоритма решения задачи модуля в целом;
- руководствуясьразработанным алгоритмом, реализация отдельных подпрограмм и методов;
- тестированиеотдельных подпрограмм и методов в автономном режиме, с проверкой входных ивозвращаемых значений;
- компоновкаподпрограмм в отдельный модуль;
- проверкасинтаксиса модуля в целом;
- компиляциямодуля;
- обнаружениеи исправление ошибок в работе отдельных подпрограмм и при необходимости возвратк пункту 3;
- проведениефункционального тестирования с целью выявления ошибок при работе с данными изобласти допустимых значений, граничными (находящиеся на границе областидопустимых значений), выходящими за границу области допустимых значений.
- переходк разработке следующего модуля.
По окончанииразработки и тестирования отдельных модулей проводилась их компоновка в системумодулей составляющих собственно программу в целом, после чего осуществлялось совместноетестирование модулей с целью выявления их взаимной несовместимости на отдельныхэтапах функционирования.
С этой цельюактивно использовались средство интегрированной отладки Integrated Debugger всостав которого входят такие функции как трассировка со входом в подпрограмму(Trace Into), пошаговое выполнение программы (Step Over), использование точекостанова в коде (SourceBreakPoint), использование точек останова по адресу(AddressBreakPoint) просмотр значений идентификаторов при помощи WatchList ииспользование альтернативного, но более функционального средстваDebugInspector.
По окончанииразработки, тестирования, отладки и конкатенации модулей в единую систему, собразованием исполняемого модуля проводилось структурное тестирование функцийпрограммного комплекса в целом. С этой целью производилась какпоследовательная, так и перекрестная активация всех функциональных подсистемкомплекса. Для внешнего контроля за корректностью работы автоматизированнойсистемы, с точки зрения операционной системы Windows, были использованы дополнительныесредства тестирования.
BorlandWinSight – использовался для визуализации иерархической системы окон проекта иисследовании потока системных сообщений в адрес элементов управления проекта.
Еще одноинструментальное средство, которое использовалось при структурном тестированиипроекта – Spy32 for Windows9x/NT. Программа Spy32 позволила протестироватьфункционирование отдельных элементов интерфейса путем обращения к ихобработчикам на уровне системных сообщений.
Корректностьсовместной работы проекта с менеджером памяти Windows позволил осуществитьпрограммный комплекс NuMega BoundsChecker. Правильность обращений к рееструбыли проконтролированы при помощи Registry Monitor от Sysinternals Corp./>/>4.4 Описание программы
Автоматизированнаясистема для оценки уровня знаний студентов с применением технологии«Клиент-сервер» предназначена для проведения централизованных итоговых занятийпо разным дисциплинам в виде интерактивного тестирования.
Данный проектподдерживает совместимость с пакетом Microsoft Office в применении единогоформата данных и обеспечивает передачу данных в стандартные средства MS Office,такие как MS Word и MS Excel.
Автоматизированнаясистема представляет собой совокупность двух программ HL Server и HL Client.
Программа HL Server – предназначенадля координации процесса тестирования, формирования и редактирования базытеста, генерации информации необходимой для осуществления тестирования.
HLClient – программа,предназначена для осуществления двусторонней связи с ведущим компьютером длядиалога с преподавателем, передачи информации о ходе тестирования каждогоученика и служебных данных обеспечивающих корректную работу сетевой подсистемыпроекта.
Установка АСТначинается с запуска хранителя дистрибутива. Далее необходимо следоватьинструкциям по установке.
В процессеустановки все файлы, необходимые для функционирования АСТ, помещаются всистемную директорию («C:\Programm Files\HLTest»), имеющую приуспешной установке пакета, следующее структурное содержание:
- файл HLServer.exe – главныйисполняемый модуль;
- каталогGroups – содержит текстовыефайлы имеющие системное имя студенческой группы, содержимое данного файла –список фамилий студентов данной группы;
- каталогQuestions – содержин каталоги с наименованием дисциплин, каждый из которыхсодержит Базу Теста в виде каталога, имеющего имя преподавателя по данномупредмету.
Запускпрограммы HLServer можно осуществить по выбору при помощи созданного, впроцессе установки, ярлыка HLTest.lnk на рабочем столе, либо выбором в менюПуск – Программы – HLTest – HLServer.lnk.
При запускепроисходит выделение необходимых для ее функционирования ресурсов иинициализация переменных окружения, таких как параметры интерфейса и рабочаядиректория, локальный IP адрес.
В зависимостиот целей запуска программы HLServer можно начать работать над созданием иливедением базы теста, формированием пакета теста или же начать тестирование.
Перед началомтестирования необходимо проверить работоспособность сети в целом, позаботитьсяо распространении (при помощи стандартных сетевых средств операционной системы)и активации пакета теста путем запуска программы HLClient.exe на всехкомпьютерах.
Призавершение работы HLServer происходит инструктирование всех подключенных рабочихстанций (если таковые имеются) о необходимости в освобождении занимаемых имиресурсов.
При шаговомпереходе по записям производится контроль над выходом за границы массивазаписей, при котором выводится соответствующее сообщение. Для удобства переходак необходимым билетам, организован визуальный навигатор, позволяющий быстроперейти к нужному билету. Использование навигатора позволяет обойти алгоритмконтроля над выходом за границы массива записей.
Приформировании нового билета происходит контроль над вводимыми значениями, такпри не заполнении одного из полей билета или отсутствии выбора верного ответа,выдается сообщение о необходимости дополнить веденную информацию.
При выбореподпункта «Закрыть» на экран выводится диалог, позволяющий выбрать междузакрытием базы теста и отменой действия. При положительном ответе происходитзакрытие текущей базы теста, освобождение занимаемых ресурсов и выводсоответствующего сообщения.
При выбореподпункта «Удалить» на экран выводится диалог, позволяющий выбрать междуудалением базы теста и отменой действия. При положительном ответе происходитудаление и оповещение о результате выполнения операции.
Приподключении новых клиентов к серверу происходит сетевой запрос информации оклиенте, ответ на который включает следующие поля:
- Ф.И.О.студента;
- группаобучения;
- статусстанции (готов к тестированию, проходит тестирование, окончил тестирование);
- количествоверных ответов;
- количествоошибок;
- общеечисло пройденных билетов;
- IP –адрес станции.
Существуетвозможность в любой момент отключить станцию от сервера, для этого необходимовыбрать станцию подлежащую отключению и щелкнуть на кнопке – «Отключить» вглавной форме.
Предусмотренавозможность остановки тестирования по времени. При вводе времени, по истечениюкоторого, тестирование должно прекратиться, происходит контроль закорректностью ввода формата времени, так если в поле содержащем количествосекунд будет введено число большее чем 60, будет выведено сообщение об ошибкепри вводе времени.
Предварительныйпросмотр отчета успеваемости можно просмотреть щелкнув на кнопке «Отчетуспеваемости» в главной форме при этом откроется форма содержащая отчетуспеваемости, информацию из которой, можно направить в MS Word для дальнейшейраспечатки.
Функционированияавтоматизированной системы на клиентской стороне начинается с активации пакетатеста путем запуска программы HLClient.exe входящей в состав пакета.
После запускепрограммы HLClient в центре экрана появляется форма, в которой тестируемый студентдолжен выбрать код группы, в которой он проходит обучение и свою фамилию, покасоответствующие поля не будут заполнены продолжение работы программыневозможно. По окончании выбора необходимо нажать на кнопку «Начатьтестирование», что приведет к появлению на экране формы, при появлении которойпрограмма HLClient производит инициализацию и загрузку сетевых параметровсистемы и на основе полученных данных осуществляет попытку соединения ссервером теста.
Присоединении с сервером происходит двунаправленная пересылка данных, необходимыхдля дальнейшего функционирования программ HLClient и HLServer как единойавтоматизированной системы.
Послепрохождения теста осуществляется подсчет числа верных ответов, ошибок исравнение полученных значений с критерием оценки. Вывод оценки осуществляется ввиде сообщения на главной форме. По прошествии 6 секунд после появлениясообщения с оценкой, на экран выводится сообщение «Ждите окончаниятестирования».
Далееклиентская сторона АСТ вновь переходит в режим ожидания сигнала-окончаниятестирования, при получении которого происходит закрытие программы HLClient.
5. Мероприятия по охране труда, технике безопасности ипротивопожарной защите
В целяхобеспечения охраны труда и техники безопасности в ГОУ СПО «Тульскийэкономический колледж» предусмотрены следующие меры:
- все видеотерминалысоответствуют требованиям европейского стандарта TCO'99;
- в соответствии севропейскими требованиями по организации рабочего места с использованиемвычислительной техники и во избежание повреждения внутренних и внешнихустройств вычислительной от статического электричества произведено ихзаземление;
- используются сетевыефильтры и источники бесперебойного питания;
- используются каквнутренние, так и внешние кондиционеры воздуха.
Наподоконниках располагаются растения, у которых под действием солнечной энергии(лучей света) протекает процесс фотосинтеза, в результате чего листья растенийпоглощают углекислый газ (СО2) и выделяют кислород (О2),тем самым фильтруя воздух в лаборатории.
В соответствии с ГОСТ 12.1.005–88 «Общие санитарно-гигиеническиетребования к воздуху рабочей зоны», в рабочих помещениях постоянноподдерживается постоянная температура воздуха 20–24 градусов по шкале Цельсия,относительная влажность 40–60% и скорости движения воздуха не более 0,1 м/с.
Перепад температуры по высоте рабочей зоны допускается до 3С0,по горизонтали до 5С0.
Интенсивность теплового облучения работающих от нагретыхповерхностей оборудования, осветительных приборов не должна превышает 35 Вт/кв.м при облучении 50% поверхности тела, 70 Вт/кв. м – при величине облучаемойповерхности от 25% до 50% и 100 Вт/кв. м при облучении не более 25% поверхноститела.
Уровень электромагнитного излучения установлен ГОСТом 12.1.006–84ССБТ. «Электромагнитные поля радиочастот. Допустимые уровни на рабочих местах итребования к проведению контроля».
Уровни инфракрасногои ультрафиолетового излученияустановлены ГОСТом 27.016–86. «Дисплей; Трубки электронно-лучевые приемные».
Уровень шума, создаваемый вентиляционной системой не превышаетдопустимого уровня в 70 Дба, уровень шума от принтера HP 690C соответствует ISO9296 и составляет 50 Дба, что не превышает 55 Дба установленных в ГОСТ 12.1.003–83.«Шум. Общие требования безопасности».
Каждый день проводится влажная уборка, что обеспечиваетсоответствие с требованиями СН 512–78 «Инструкция по проектированию зданий ипомещений ЭВМ» запыленность воздуха в рабочем помещении, и не превышаяпредельно допустимуюконцентрацию(ПДК), равную 2 мг/куб. м, инаходится в пределах нормы, специально для этой работы имеется техническийперсонал в количестве одного человека.
Всекомпьютерное оборудование, используемое в ГОУ СПО «Тульский экономическийколледж» питается от сети переменного тока напряжением 220В, частотой 50Гц.
Техникабезопасности при работе с электрооборудованием направлена, прежде всего, напредотвращение случаев поражения электрическим током. Перед первым включениемкомпьютера следует проверить, соответствует ли напряжение в сети тому, накоторое рассчитан компьютер (многие компьютеры могут работать при несколькихзначениях входного напряжения, например при 220 В или 110 В). При необходимостинадо установить переключатель напряжения на компьютере в правильное положение.
Хотявстроенные в компьютеры блоки питания, преобразующие напряжение электросети внизковольтное напряжение (±12 В и ±5 В), достаточноустойчивы и работают даже при понижении или повышении напряжения на 10–15%,однако далеко не всегда обеспечивают безопасность компьютеров и их устойчивуюработу. С этой целью в ГОУ СПО «Тульский экономический колледж» на питание накомпьютеры подаётся через средства защиты от недостатков электропитанияподключенных по следующей схеме: стабилизатор Штиль 500 -> сетевой фильтр Pilot 1200F -> бесперебойного питания APC Back UPS CS 500.
Наибольшую опасность представляет двухполюсноеприкосновение человека к токоведущим частям, когда он оказывается под полнымрабочим напряжением сети.
Допустимые значения напряжения прикосновения итока, протекающего через тело человека, регламентированы ГОСТом 12.038–82 иоцениваются по трем критериям электробезопасности:
1. Ощутимый ток. Не вызывает нарушениядеятельности организма и допускается для длительного протекания. Сила тока дляпеременного тока 0,3 МА. Сила тока для постоянного тока 1 МА.
2. Отпускающий ток. Его действие на человекадопустимо, если длительность протекания не превышает 30 секунд. Сила дляпеременного тока 6 МА. Сила для постоянного тока 15 МА.
3.Фибриляционный ток. Допускается воздействие не более 1 секунды. Сила дляпеременного тока 50 МА. Сила для постоянного тока 200 МА.
Технические иорганизационные меры защиты обеспечивают недоступность токопроводящих частей иневозможность случайного прикосновения к ним, устраняют опасность поражения призамыкании на корпус или на землю.
Техникабезопасности электрооборудования включает в себя следующие виды защиты отпоражения током:
– ограждениетокопроводящих частей;
– блокировку;
– предупредительныенадписи;
– двойнуюизоляцию корпусов;
- изоляцию токопроводящихчастей;
- защитное разделениепитания;
- защитноезаземление металлических частей корпусов.
Освещенностьрабочего места должна удовлетворять требованиям СНиП 11–4–79 «Строительныенормы. Нормы проектирования. Естественное и искусственное освещение». Освещениепри работе с ЭВМ должно быть смешанным: естественное (боковое или прямое) иискусственное (общее). Искусственное освещение должно осуществляться с помощьюлюминесцентных ламп. При естественном освещении должны применяться средствасолнцезащиты (светорассеивающие шторы или жалюзи). Для исключения бликовотражения на экране применяются антибликовые покрытия, специальные фильтры идругие средства предусмотренные заводом изготовителем оргтехники в целяхобеспечения соответствия с европейским стандартом TCO'99.
Для освещения кабинета используются естественные и искусственныеформы, то есть в дневное, не пасмурное, время суток в качестве естественнойформы освещения выступает Солнце, а в качестве искусственной формы освещенияиспользуются люминесцентные лампы. Для поступления солнечных лучей в кабинетахимеются три окна со светорассеивающими шторами.
В соответствии с требованиями СНиП 11–4–79 уровень освещенности нарабочем месте при искусственном освещении должен быть не менее 300 лк вкабинетах колледжа этот показатель составляет в среднем 323 лк.
Элементы рабочего места – рабочее кресло и стол должнысоответствовать требованиям ГОСТа 12.2.032–78 и ГОСТа 21889–76.
Площадь помещений для работников ВЦ следует предусматриватьвеличиной не менее 6.0 м^2 на человека. В соответствии с ВСНиП 4559–88рабочий стол должен регулироваться по высоте в пределах 680–760 мм.Оптимальные размеры рабочей поверхности столешницы 1600x900 мм. Подстолешницей рабочего стола должно быть свободное пространство для ног сразмерами по высоте не менее 600 мм, по ширине 500 мм, по глубине 650 мм.На поверхности рабочего стола для документов необходимо предусмотретьразмещение специальной подставки, расстояние которой от глаз должно бытьаналогичным расстоянию от глаз до клавиатуры, что позволяет снизить зрительноеутомление.
Рабочий стул (кресло) должен обеспечивать удобную посадку приработе и обладало следующими функциональными возможностями:
- Устойчивое основание,например, пять ножек на роликах. Конструкция ножек должна соответствоватьповерхности пола, независимо от того, гладкий он или с ковровым покрытием.
- Возможность регулировкикресла по высоте и углу наклона. Высота кресла должна легко регулироваться впределах от 40 до 52 см (считается расстояние от пола до сиденья). Еслирост выше или ниже среднего, может потребоваться кресло с большим диапазономрегулировки. Необходимо отрегулировать кресло таким образом, чтобы рабочаяповерхность или полка для клавиатуры были на уровне локтя, ступни ног полностьюстояли на полу, а колени согнуты и расположены немного ниже бедер. В идеальномслучае сиденье кресла должно наклоняться как вперед (минимум на 5 градусов),так и назад (минимум на 10 градусов). Если кресло имеет регулируемое сиденье,необходимо наклонить его немного вперед. Это перенесет нагрузку с позвоночникана бедра и ступни, уменьшив нагрузку на спину.
- Изогнутый край сиденья.Передняя часть сиденья должна быть изогнута и иметь мягкие края.
- Регулируемая по высоте инаклону спинка. Очень важно, чтобы спинка плотно прилегала к нижней части спины(пояснице).
- Легко вращающеесяоснование, которое позволяет свободно поворачиваться в обе стороны.
- Полностью регулируемые имягкие подлокотники. Подлокотники не должны препятствовать регулировке кресла имешать вплотную придвигаться к рабочей поверхности.
На рабочемместе необходимо предусматривать подставку для ног.
В соответствиис эргономическими требованиями, установленными ГОСТом 21829–76 ВДТ долженотвечать следующим требованиям:
- яркость свечения экранане менее 100 кд/м2;
- минимальный размерсветящейся точки – не более 0.4 мм;
- контрастность изображениязнака – не менее 0.8;
- экран должен иметьантибликовое покрытие.
В настоящеевремя установлены жесткие стандарты безопасности на современные мониторы, чтопонижает риск ухудшения самочувствия при работе с ними. Клавиатура не должнабыть жестко связана с монитором.
Большой опасностью для любого предприятия являются пожары,наносящие немалые убытки. Главными причинами возникновения пожаров напроизводстве являются:
- короткое замыкание;
- повышенная температураокружающих предметов;
- неисправноеэлектрооборудование или неправильная его эксплуатация.
Пожарнаяпрофилактика – это комплекс организационных и технических мероприятий,направленных на обеспечение безопасности людей, на предотвращение пожара,ограничение его распространения, а также на создание условий для успешноготушения пожара.
Во избежаниепожара или взрыва, необходимо строго выполнять противопожарные мерыбезопасности.
Устройство иэксплуатация оборудования, зданий и сооружений должны соответствоватьтребованиям противопожарной безопасности.
Для прекращения процесса горения используютсяследующие основные меры:
– Охлаждение горящих веществ путемнанесения на их поверхность теплоемких огнетушащих средств (воды, пены и т.д.)или перемешивания слоев горящей жидкости.
– Разбавление концентрации горючих паров,пыли и газов путем введения в зону горения инертных газов (азот, углекислыйгаз).
– Изоляция горящих веществ от зоны горениянанесением на их поверхность изолирующих огнегасительных средств (пены, песка,кашмы).
– Химическоеторможение реакции горения путем орошения поверхности горящих материалов илиобъемного разбавления горючей пыле – газо- и паровоздушной системыфлегматизирующими веществами и составами.
Противопожарныемеры ГОУ СПО «Тульский экономический колледж» заключаются в следующем:
- в коридорах висят планыэвакуации в случае пожара;
- имеется пожарный кран вкоридорах на каждом этаже и огнетушители типа ОХВП-10 в каждом кабинете.
/>/>6.Экономическая часть/>/> 6.1 Расчет себестоимости программногопродукта
В экономической части дипломного проектарассчитывается себестоимость программного продукта.
Исходные данные длярасчёта себестоимости программного продукта приведены в таблице 1.
Таблица 1. Исходныеданные
Наименование
Значение
Количество форм входной информации
Из них:
переменной
нормативно-справочная
банка данных
3
2
1
Количество разновидностей форм выходной информации 1
Степень новизны задачи
Б
Сложность алгоритма
1
Вид используемой информации
ПИ
Сложность контроля:
входной информации
выходной информации
12
22
Язык программирования
Borland Delphi 6.0
Вид обработки
Режим реального времени (РВ)
Алгоритм расчёта себестоимости программногопродукта:
анализ исходных данных;
расчёт трудоёмкости разработки программногопродукта;
расчёт стоимости машинного часа;
расчёт стоимости программного продукта;
Расчёт трудоёмкости разработки программногопродукта по стадиям представлен в Таблице 2.
Таблица 2.Трудоёмкость разработки по стадиям Стадия разработки проекта Затраты времени Поправочный коэффициент Затраты времени с учётом поправочного коэффициента Значение Значение 1 2 3 4 1. Разработка технического задания 1.1. Затраты времени разработчика постановки задачи 15 0,65 9,5 1.2. Затраты времени разработчика программного обеспечения 15 0,35 5,25 2. Разработка эскизного проекта 2.1. Затраты времени разработчика постановки задачи 34 0,7 23,8 2.2. Затраты времени разработчика программного обеспечения 34 0,3 10,2 3. Разработка технического проекта 3.1. Затраты времени разработчика постановки задачи 9 1,827 16,443 3.2. Затраты времени разработчика программного обеспечения 5 1,827 9,135 4. Разработка рабочего проекта 4.1. Затраты времени разработчика постановки задачи 3 3,6936 11,0808 4.2. Затраты времени разработчика программного обеспечения 27 3,6936 99,7272 5. Внедрение 5.1. Затраты времени разработчика постановки задачи 5 1,39 6,95 5.2. Затраты времени разработчика программного обеспечения 5 1,39 6,95
Время работыЭВМ при отладке и внедрении программы складывается из затрат времениразработчика программного обеспечения на технический проект, рабочий проект ивнедрение.
Такимобразом, затраты времени на отладку и внедрение составляют 49 человеко-дней или392 часов.
/>/>6.1.1 Расчёт стоимости одного машинного часа.
Стоимость одного машинного часа определяется по формуле/>, где (7)
Эксп – эксплуатационныегодовые затраты (в рублях);
Тф – количество часов,отработанных всеми машинами в год (час).
Эксплуатационныегодовые затраты включают в себя:
1 Годоваяамортизация оборудования (Аоб), формула 8;
2 Годовыезатраты на ремонт оборудования (Роб), формула 9;
3 Расходына электроэнергию (Зэл), формула 10;
4 Прочиерасходы (Зпр), формула 14.
1. Годоваяамортизация оборудования определяется:/>, где (8)
Косн–коэффициент амортизации основного оборудования (в процентах);
Сосн – стоимость основногооборудования (в рублях);
Квсп – коэффициентамортизации вспомогательного оборудования (в процентах);
Свсп – стоимостьвспомогательного оборудования (в рублях).
В данномслучае стоимость одного принтера пропорционально распределена между двумя компьютерами.
/> руб.
2. Годовыезатраты на текущий ремонт составляют 5% от общей стоимости используемогооборудования.
/>, где (9)
Собщ – общая стоимостьоборудования (в рублях).
/> руб.
3. Затраты наэлектроэнергию складываются из расходов на освещение Вос (формула10) и расходов на производственное потребление электроэнергии Вэ (формула11).
Зэл=Вос+Вэ, где (10)
Вос – расходы на освещение (врублях);
Вэ – расходы напроизводственное потребление электроэнергии (в рублях).
/>, где (11)
S – площадь помещения (вквадратных метрах);
Кэ – усреднённый расходэнергии, для освещения одного квадратного метра площади помещения в год (кВт наквадратный метр);
Стар – тариф (в рублях).
/> руб.
/>, где (12)
Нуст–мощность одного компьютера (кВт);
Н – количество компьютеров(штук);
К – коэффициент учитывающийпотери в сети;
Стар– тариф(в рублях);
Ф – годовой фонд времениработы оборудования рассчитывается по формуле:/>, где (13)
Нг – число дней в году;
Нвых– числовыходных дней в году;
Нпр– числопраздничных дней в году;
Ксм–коэффициент сменности;
Фдн–продолжительность рабочего дня;
Кзаг–коэффициент загрузки оборудования;
Крем–коэффициент, учитывающий потери времени на ремонт оборудования.
/> часа.
Тогда расходына производственное потребление электроэнергии (по формуле 12) равны /> руб.
Затраты на электроэнергию (по формуле 10) равны /> руб.
4. Прочиерасходы составляют 5% от суммы расходов по предыдущим пунктам./>, где (14)Аоб– сумма годовой амортизации (в рублях);Робщ– годовые затраты на ремонт (в рублях);Э –расходы на электроэнергию (в рублях)./>/> руб.Тогда эксплуатационные годовые расходысоставляют:/>, где (15)Аоб – сумма годовой амортизации (в рублях);Робщ– годовые затраты на ремонт (в рублях);Э –расходы на электроэнергию (в рублях);Зпр– прочие расходы (в рублях).
/> руб.
Количествочасов, отработанных всеми машинами в год равно:/>, где (16)
Н – количество компьютеров(в штуках);
Ф – годовой фонд времениработы оборудования (в часах)./> часовТогда стоимость одного машинного часа (поформуле 7) равна:/> руб./>/> 6.1.2 Расчёт стоимости программного продукта.
Стоимостьпрограммного продукта определяется по формуле:
/>, где (17)
Тдн – затраты времени наразработку (чел.-дней);
Змес–среднемесячная зарплата (в рублях);
Ндн–количество рабочих дней в месяце (дни);
Тмаш–затраты времени на отладку и внедрение (в часах);
См.ч. – стоимость одногомашинного часа (в рублях)./> руб.
/>/>Заключение
В данном дипломном проекте представлена «Автоматизированнаясистема контроля знаний на основе архитектуры клиент-сервер», реализованная всреде программирования Borland Delphi 6.0.
Дополнительныесредства разработки и возможности среды программирования позволили осуществитьформирование и ведение базы теста, вывод необходимых форм и отчетауспеваемости, создать удобный пользовательский интерфейс включающий:
· стандартная строка меню;
· кнопки – для активизации функцийсистемы;
· сопроводительные сообщения.
Дляповышения надежности хранения информации предусмотрены программные средствазащиты информации:
· резервное сохранение базы теста;
Наличиевстроенной контекстной помощи позволяет упростить использование программы.
Дипломныйпроект был выполнен в заданный срок.
/>/>Приложение1Листинг кода сервернойчасти программы
program HLServer;
uses
Forms,
BaseUnit in 'BaseUnit.pas'{MainForm},
QBaseWork in 'QBaseWork.pas',
UBaseWork in 'UBaseWork.pas';
{$R *.res}
begin
Application. Initialize;
Application. CreateForm (TServerForm,ServerForm);
Application. Run;
end.
unit BaseUnit;
interface
uses
QBaseWork, UBaseWork, Windows,Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, Grids, StdCtrls,ExtCtrls, Menus, CommCtrl, ComCtrls,
IniFiles, WinSock, ComObj, OleServer,Word97, ShellCtrls, Buttons, Word2000;
const
NM_Register1 = 6; // прием списка групп
NM_Register2 = 7; // запрос на списокстудентов
NM_RegisterGetWorks = 66; // запрос /ответ 'список предметов'
NM_RegisterGetTeachers = 77; // запрос /ответ 'список преподователей'
NM_RegisterOK = 8; // клиентзарегистрирован
NM_Service = 31; // прием сервиснойинформации
NM_TestEvent = 55; // событие по ходутестирования
NM_FileOperation = 10; // сетевая операцияс файлами
NM_EndOfTest = 33; // окончаниетестирования
NM_KickFromServer = 44; // отключение отсервера администратором
NM_OutOfTime = 50; // отключение поистечении времени
NM_DataError = 54; // проблема с БД
NM_Wait = 61;
type
PCustomWinSocket=TCustomWinSocket;
Questions=record // Структура вопроса
Passed:boolean; // пройден (да/нет)
Style:byte; // стиль вопроса {radio,check, memo}
UserAnswer: word; // ответ пользователя
TrueAnswer: word; // верный ответ
end;
PathID=record
WorkID:byte;
TeacherID:byte;
end;
Peoples=record // структура 'Пользователь'
SocketHandle: Integer; // дескриптор соединения
Ip:string[15]; //IP адрес
Num:byte; // номер клиента
Registered:boolean; // прошел регистрацию(да/нет)
TestingAbortedByTime:boolean;
Group:string[8]; // группа
Name:string[20]; // имя
Teacher:string[40]; // преподаватель
WorkName:string[40]; // наим. дисциплины
WorkPath:string[255]; // рабочаядиректория пользователя
UserWorkPathID: PathID; // идентификаторы дисциплиныи преподавателя
ImageType:string[3]; // тип файла вопросов{зарезервировано}
QuestCount:byte; // количество вопросов
OpenQuest:byte; // Ссылка на билет измассива Questions
// для дальнейшего
TimeLater:TTime; // потрачено времени
SumTime:TTime; // общий бюджет бремени
PassedCount:byte; // пройдено вопросов
True_:byte; // верных ответов
False_:byte; // неверных ответов
Mark:byte; // оценка
PassTest:boolean; // тест пройден (да/нет)
Questions:array [1..255] ofQuestions; // массив пройденных вопросов
end;
type
TServerForm = class(TForm)
ServerSocket1: TServerSocket;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
ComboBox1: TComboBox;
ListBox1: TListBox;
Label2: TLabel;
Label3: TLabel;
Timer1: TTimer;
Label4: TLabel;
Label5: TLabel;
TabSheet4: TTabSheet;
ConnectionCount: TLabel;
Timer2: TTimer;
TabSheet8: TTabSheet;
Panel3: TPanel;
Button3: TButton;
Button4: TButton;
Image1: TImage;
RadioGroup1: TRadioGroup;
ShellTreeView1: TShellTreeView;
ShellListView1: TShellListView;
ComboBox2: TComboBox;
Bevel8: TBevel;
Label1: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
Label16: TLabel;
Label10: TLabel;
Label17: TLabel;
Label18: TLabel;
Bevel1: TBevel;
Bevel4: TBevel;
Bevel5: TBevel;
Bevel6: TBevel;
Bevel7: TBevel;
Bevel9: TBevel;
Bevel13: TBevel;
Bevel10: TBevel;
Bevel11: TBevel;
Bevel12: TBevel;
Bevel14: TBevel;
Bevel15: TBevel;
Bevel16: TBevel;
Bevel17: TBevel;
Bevel18: TBevel;
Bevel19: TBevel;
Bevel20: TBevel;
WordDocument1: TWordDocument;
SpeedButton1: TSpeedButton;
PageControl2: TPageControl;
TabSheet3: TTabSheet;
TabSheet5: TTabSheet;
StringGrid1: HLringGrid;
StringGrid2: HLringGrid;
TabSheet6: TTabSheet;
Memo1: TMemo;
Button7: TButton;
Button8: TButton;
SaveDialog1: TSaveDialog;
Panel2: TPanel;
Label29: TLabel;
Label30: TLabel;
Label31: TLabel;
Label32: TLabel;
TabSheet7: TTabSheet;
ReportGrid: HLringGrid;
Button1: TButton;
procedure ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure FormCreate (Sender:TObject);
procedure FormDestroy (Sender:TObject);
procedure ServerSocket1ClientRead (Sender:TObject;
Socket: TCustomWinSocket);
procedure ComboBox1Change (Sender:TObject);
procedure Timer1Timer (Sender:TObject);
procedureServerSocket1ClientDisconnect (Sender: TObject;
Socket: TCustomWinSocket);
procedure Timer2Timer (Sender:TObject);
procedure StringGrid1DblClick (Sender:TObject);
procedure Button3Click (Sender:TObject);
procedure ShellListView1Change (Sender:TObject; Item: TListItem;
Change: TItemChange);
procedure ShellListView1DblClick (Sender:TObject);
procedure Image1Click (Sender:TObject);
procedure ShellTreeView1Enter (Sender:TObject);
procedure ServerSocket1ClientError (Sender:TObject;
Socket: TCustomWinSocket;ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure Button1Click (Sender:TObject);
procedure SpeedButton1Click (Sender:TObject);
procedure StringGrid1SelectCell (Sender:TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
procedure Button7Click (Sender:TObject);
procedure Button8Click (Sender:TObject);
private
function DecodeNumToSocketNum (StationNum:byte): byte;
procedure SendQuestion (ForStation:byte; TheFile: String; QuesHLyle:byte; TrueAnswer: Word);
procedure TestEvent (StationNum:byte; Socket_:PCustomWinSocket);
procedure SendFileMessage (var Message:TMessage); message WM_USER;
procedure LogMessage (var Message:TMessage); message WM_USER+2;
procedure FillReportTable;
procedure CreateReport;
procedure TableClear (Table:HLringGrid);
procedure ReFillTable;
procedure CriticalClientDisconnect (Ip,Name, Group, WorkName,
TeacherName: String; TrueAnsw,FalseAnsw: byte; TimeLater: TTime);
procedure TimeRefresh;
procedure ProblemWithData (From_:PCustomWinSocket;TxtMessage: string);
procedure AddLogMessage (Message_:string);
procedure DisconnectComboBoxUpdate;
procedure TimeOUTTesting (StationNum:byte);
// functionDecodeSocketToClientNum (Socket_: THandle): byte;
end;
var
ServerForm: TServerForm;
FOptions:TIniFile;
NetworkErrors:word;
RootPath:string;
DataSetForReport:array [0..44] ofPeoples;
CurrenHLation:byte;
GroupList: String;
RegisteredClients:byte;
PassedTestCount:byte;
ConnectedSumm:byte;
// TimeForPassTest:TTime;
SelectedRow:integer;
CurrentQuestFile:string;
CurrentQuestionNum:integer;
DoAction:boolean;
QUESTIONBASE:TQuestDB;
USERSBASE:TUsersDB;
SecCounter:byte;
Processing:boolean;
implementation
{$R *.dfm}
procedure TServerForm. SendQuestion (ForStation:byte;TheFile: String; QuesHLyle: Byte; TrueAnswer: Word); // Отправка вопроса
var FileStream:TMemoryStream; //Файловый поток
Command:byte; // Команда
procedure LoadFileForSend (const FileName:string); // Локальная процедура подготовки
var Stream: HLream; // файлового потока
Count: Int64; // размер файла данных
MakePointer:DWORD; // искусственныйуказатель
CurrSize: Int64; // размер файловогопотока
FNameLen:byte; // длина имени файла (длякорректного распознавания на стороне клиента)
begin
Stream:= TFileStream. Create (FileName,fmOpenRead or fmShareDenyWrite); // создаем поток
try
Count:= Stream. Size;
Stream. Position:=0;
// далее переносим информацию в поток
FileStream. WriteBuffer (Count, SizeOf(Int64)); //размер файла данных
FNameLen:=Length(FileName);
FileStream. WriteBuffer (FNameLen, 1); //длина имени файла
FileStream. WriteBuffer (Pointer(FileName)^,FNameLen); // имя файла
FileStream. Position:=0;
CurrSize:=FileStream. Size;
FileStream. SetSize (Count+CurrSize); //расширяем поток (в смысле размера)
MakePointer:=DWORD (FileStream. Memory)+CurrSize;
if Count0 then Stream. ReadBuffer (Pointer(MakePointer)^, Count); // переписываем данные из потока в поток
// с использованием указателя на память
finally
Stream. Free; // освобождаем промежуточныйпоток
end;
end;
begin
try
Command:=NM_FileOperation;
FileStream:=TMemoryStream. Create;
FileStream. WriteBuffer (Command, 1);
FileStream. WriteBuffer (TrueAnswer,2);
FileStream. WriteBuffer (QuesHLyle, 1);
LoadFileForSend(TheFile);
FileStream. Position:=0;
ServerSocket1. Socket. Connections[ForStation].SendStream(FileStream); //отправка потока
except
FileStream. Free;
end
end;
// очищать неверный дисконнект
procedure TServerForm. SendFileMessage (var Message: TMessage); // внутреннее событие отправка файла
var
DataStream:TMemoryStream;
Data:byte;
StationNum:byte;
PSock:TCustomWinSocket;
begin
StationNum:=Message.WParam;
ifDataSetForReport[StationNum].PassedCount=0 then
begin
DataStream:=TMemoryStream. Create; //создаем поток
Data:=NM_Service; // код команды
DataStream. WriteBuffer (Data, 1);
Data:=DataSetForReport[StationNum].QuestCount; //количество вопросов
DataStream. WriteBuffer (Data, 1);
DataStream. WriteBuffer (DataSetForReport[StationNum].SumTime,SizeOf (DataSetForReport[StationNum].SumTime)); // время на тестирование
DataStream. Position:=0;
ServerSocket1. Socket. Connections [DecodeNumToSocketNum(StationNum)].SendStream(DataStream);
// отправка потока
sleep(1); // задержка1ms
end;
PSock:=ServerSocket1. Socket. Connections[DecodeNumToSocketNum(StationNum)];
TestEvent (StationNum,@PSock); // генерациясобытия связанного с тестированием
end;
function TServerForm. DecodeNumToSocketNum (StationNum:byte):byte; //поиск индекса станции в динамическом
var TryConnectedStation:byte; //массиве Connections по известному
begin // по номеру
Result:=0;
ifDataSetForReport[StationNum].SocketHandle0 then
forTryConnectedStation:=ServerSocket1. Socket. ActiveConnections-1 downto 0 do //перебираем все соединения
begin // поиск ведется по дескрипторусоединения
if ServerSocket1. Socket. Connections[TryConnectedStation].SocketHandle=DataSetForReport[StationNum].SocketHandlethen
begin
Result:=TryConnectedStation; // если найденасоответствующая станция,
break; // выходим предварительно
end;
end;
end;
procedure TServerForm. ServerSocket1ClientError(Sender: TObject; // ошибка соединения
Socket: TCustomWinSocket;ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ErrorCode:=0;
DoAction:=true;
Inc(NetworkErrors);
Socket. Close;
end;
Procedure TServerForm. AddLogMessage(Message_:string);
begin
SendMessage (Handle, WM_User+2, DWord(PChar(Message_)), 0);
end;
procedure TServerForm. ServerSocket1ClientConnect(Sender: TObject; // соединение
Socket: TCustomWinSocket);
var ConnectionsScan:byte;
ConnectedClientNum:byte;
Buff:string;
Command:byte;
ConnectOK:boolean;
procedure KickFromServer;
begin
Command:=NM_KickFromServer;
Socket. SendBuf (Command, 1);
end;
begin
AddLogMessage (Socket. RemoteAddress+'Has client connection, check Socket…');
ConnectOK:=false;
if ServerSocket1. Socket. ActiveConnections
begin
for ConnectionsScan:=0 to 44 do // ищем пустую ячейку (т. к. кто-то мог отсоединится)
begin
if(DataSetForReport[ConnectionsScan].SocketHandle=0) and (not (DataSetForReport[ConnectionsScan].PassTest)) then // еслинашли сохраняем ее номер и идем дальше
begin
ConnectedClientNum:=ConnectionsScan;
DataSetForReport[ConnectionsScan].SocketHandle:=Socket.SocketHandle; // Заполняем ячейку буфера соединений
DataSetForReport[ConnectionsScan].Num:=ConnectedClientNum;
Buff:=Char (NM_Register1)+Char(ConnectionsScan)+GroupList+'>'; //список групп и персональный номер
Socket. SendBuf (Pointer(Buff)^, Length(Buff)); //отправка буфера
CurrenHLation:=ConnectedClientNum;
ConnectOK:=true;
AddLogMessage (Socket. RemoteAddress+'Client accepted');
break;
end;
end;
end else AddLogMessage (Socket. RemoteAddress+'Server is Full');
if not ConnectOK then
begin
AddLogMessage (Socket. RemoteAddress+'Client not accepted');
KickFromServer;
end;
Inc(ConnectedSumm); // увеличиваем счетчик соединений
end;
procedure TServerForm. CriticalClientDisconnect(Ip:string; Name, Group, WorkName, TeacherName: String; TrueAnsw, FalseAnsw:byte;TimeLater:TTime);
var i:byte;
begin
if Ip'' then
for i:=1 to StringGrid2. RowCount-1do
begin
if StringGrid2. Cells [0, i]='' then
begin
StringGrid2. RowCount:=i+2;
StringGrid2. Cells [0, i]:=Ip;
StringGrid2. Cells [1, i]:=Name+''+Group;
StringGrid2. Cells [2, i]:=WorkName;
StringGrid2. Cells [3, i]:=TeacherName;
StringGrid2. Cells [4, i]:=IntToStr (TrueAnsw+FalseAnsw);
StringGrid2. Cells [5, i]:=IntToStr(TrueAnsw);
StringGrid2. Cells [6, i]:=IntToStr(FalseAnsw);
StringGrid2. Cells [7, i]:=TimeToStr(TimeLater);
break;
end;
end;
end;
procedure TServerForm. ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
var ScanConnections:byte;
DisconnectedClientNum:integer;
begin
for ScanConnections:=44 downto 0 do //перебираем все возможные подключения
begin
ifDataSetForReport[ScanConnections].SocketHandle=Socket. SocketHandle then //ищем отключившуюся станцию
begin
DisconnectedClientNum:=ScanConnections;
if notDataSetForReport[DisconnectedClientNum].PassTest then // Если станция отключилась до окончания тестирования
// то исключить ее из отчета
begin
AddLogMessage (Socket. RemoteAddress+'Client critical disconnect');
CriticalClientDisconnect (
DataSetForReport[DisconnectedClientNum].Ip,
DataSetForReport[DisconnectedClientNum].Name,
DataSetForReport[DisconnectedClientNum].Group,
DataSetForReport[DisconnectedClientNum].WorkName,
DataSetForReport[DisconnectedClientNum].Teacher,
DataSetForReport[DisconnectedClientNum].True_,
DataSetForReport[DisconnectedClientNum].False_,
DataSetForReport[DisconnectedClientNum].TimeLater
);
DataSetForReport[DisconnectedClientNum].Name:='';
ifDataSetForReport[ScanConnections].Registered then
begin
Dec(RegisteredClients);
DataSetForReport[ScanConnections].Registered:=false;
DisconnectComboBoxUpdate;
end;
ZeroMemory (Addr(DataSetForReport[DisconnectedClientNum].Questions),254);
break;
end;
AddLogMessage (Socket. RemoteAddress+'Client pass test and disconnect');
DataSetForReport[ScanConnections].PassedCount:=0;
DataSetForReport[ScanConnections].SocketHandle:=0; //обнуляем соответствующую ячейку
DataSetForReport[ScanConnections].Num:=0;
ConnectionCount.caption:=inttostr(ConnectedSumm);
DoAction:=true;
break;
end;
end;
Dec(ConnectedSumm);
if ConnectedSumm=0 then AddLogMessage(' Server is empty');
end;
procedure TServerForm. ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
type TDataBuffer=array of byte;
var
Command:byte; // собственно команда
SendLen:integer; // Длина всего принятогопотока
DataBuffer:TDataBuffer;
ClientNum:byte;
FieldNum:byte;
NameBuf:string;
SendBuff:string;
BuffLen:integer;
OpenedBuilet:byte;
UserAnswer: Word;
Wait:byte;
Procedure SetMark;
begin
ifDataSetForReport[ClientNum].Questions[OpenedBuilet].TrueAnswer=UserAnswer then
begin
inc (DataSetForReport[ClientNum].True_);
inc (DataSetForReport[ClientNum].Mark);
end
else inc (DataSetForReport[ClientNum].False_);
end;
begin
Wait:=NM_Wait;
if not Processing then
begin
SendLen:=Socket. ReceiveLength;
SetLength (DataBuffer, SendLen);
ZeroMemory (DataBuffer, SendLen);
Socket. ReceiveBuf (Pointer(DataBuffer)^,SendLen);
Command:=DataBuffer[0];
ClientNum:=DataBuffer[1];
case Command of
NM_Register2:
begin
USERSBASE. SetActiveGroup (DataBuffer[2]);
SendBuff:=Char (NM_Register2)+USERSBASE.GetUsersStringList;
BuffLen:=Length(SendBuff);
Socket. SendBuf (Pointer(SendBuff)^,BuffLen);
end;
NM_RegisterGetWorks:
begin
SendBuff:=Char (NM_RegisterGetWorks);
SendBuff:=SendBuff+QUESTIONBASE. GetWorksStringList;
BuffLen:=Length(SendBuff);
Socket. SendBuf (Pointer(SendBuff)^,BuffLen);
end;
NM_RegisterGetTeachers:
begin
FieldNum:=DataBuffer[2]; // номер элемента списка
NameBuf:='';
QUESTIONBASE. TransactionUser:=Socket.RemoteAddress+' name unknown';
if QUESTIONBASE. SetActiveWork(FieldNum)then
begin
NameBuf:=QUESTIONBASE. ActivWorkName;
SendBuff:=Char (NM_RegisterGetTeachers)+SendBuff+QUESTIONBASE.GetTeachersStringList;
BuffLen:=Length(SendBuff);
Socket. SendBuf (Pointer(SendBuff)^,BuffLen);
end else ProblemWithData (@Socket, 'Errorwith Database');
end;
NM_RegisterOK:
begin
{
0 – команда
1 – № клиента
2 – Группа
3 – Ф.И.О.
4 – WorkName
5 – Teacher
}
// 1 {определение группы}
{РЕГИСТРАЦИЯ}
DataSetForReport[ClientNum].Group:=USERSBASE.GetGroupByIndex (DataBuffer[2]);
if (USERSBASE. SetActiveGroup (DataBuffer[2]))and (USERSBASE. SetActiveUser (DataBuffer[3])) then
begin
DataSetForReport[ClientNum].Ip:=Socket.RemoteAddress;
DataSetForReport[ClientNum].Name:=USERSBASE.ActiveUserName;
QUESTIONBASE. TransactionUser:=Socket.RemoteAddress+' '+DataSetForReport[ClientNum].Name+''+DataSetForReport[ClientNum].Group;
// 3 {определение дисциплины}
if (QUESTIONBASE. SetActiveWork (DataBuffer[4]))then
if (QUESTIONBASE. SetActiveTeacher (DataBuffer[5]))then
begin
DataSetForReport[ClientNum].QuestCount:=QUESTIONBASE.QuestionsCount;
DataSetForReport[ClientNum].WorkName:=QUESTIONBASE.GetWorkByIndex (DataBuffer[4]);
DataSetForReport[ClientNum].UserWorkPathID.WorkID:=DataBuffer[4];
// 4 {определение имени руководителя}
DataSetForReport[ClientNum].Teacher:=QUESTIONBASE.GetTeacherByIndex (DataBuffer[5]);
DataSetForReport[ClientNum].UserWorkPathID.TeacherID:=DataBuffer[5];
DataSetForReport[ClientNum].SumTime:=StrToTime(QUESTIONBASE. WorkTimeLimit);
AddLogMessage (Socket. RemoteAddress+''+DataSetForReport[ClientNum].Name+' '+DataSetForReport[ClientNum].Group+' Clientpassed registration');
DataSetForReport[ClientNum].Ip:=Socket.RemoteAddress;
DataSetForReport[ClientNum].True_:=0;
DataSetForReport[ClientNum].False_:=0;
DataSetForReport[ClientNum].Mark:=0;
DataSetForReport[ClientNum].TestingAbortedByTime:=false;
DataSetForReport[ClientNum].TimeLater:=StrToTime('0:00:00');
DataSetForReport[ClientNum].PassTest:=false;
DataSetForReport[ClientNum].WorkPath:=RootPath+'Questions\'+DataSetForReport[ClientNum].WorkName+'\'+DataSetForReport[ClientNum].Teacher;
DataSetForReport[ClientNum].PassedCount:=0;
DataSetForReport[ClientNum].ImageType:=QUESTIONBASE.ImgFileType;
DataSetForReport[ClientNum].Registered:=true;
DisconnectComboBoxUpdate;
CurrenHLation:=ClientNum;
Inc(RegisteredClients); // зарегистрировано клиентов
PostMessage (Handle, WM_USER, ClientNum,0);
DoAction:=true;
end else
begin
ProblemWithData (@Socket, 'Errorwith Database');
AddLogMessage (Socket. RemoteAddress+'Problem with registration, client application shutdown');
end;
end else
begin
ProblemWithData (@Socket, 'Errorwith Database');
AddLogMessage (Socket. RemoteAddress+'Problem with registration, client application shutdown');
end;
end;
NM_TestEvent:
begin
UserAnswer:=DataBuffer[2];
OpenedBuilet:=DataSetForReport[ClientNum].OpenQuest;
DataSetForReport[ClientNum].Questions[OpenedBuilet].Passed:=true;
Inc (DataSetForReport[ClientNum].PassedCount);
ifDataSetForReport[ClientNum].QuestCount=DataSetForReport[ClientNum].PassedCountthen
begin // если пройдены все билеты тозаканчиваем тестирование
DataSetForReport[ClientNum].PassTest:=true;
SetMark;
inc(PassedTestCount);
SendBuff:=Char (NM_EndOfTest)+Char (DataSetForReport[ClientNum].Mark);
ZeroMemory (Addr(DataSetForReport[ClientNum].Questions),254);
BuffLen:=Length(SendBuff);
Socket. SendBuf (Pointer(SendBuff)^,BuffLen);
end else SetMark;
PostMessage (Handle, WM_USER, ClientNum,0);
DoAction:=true;
end;
end;
end else
begin
Socket. SendBuf (Wait, 1);
beep;
end;
end;
procedure TServerForm. TimeOUTTesting(StationNum:byte);
var SendBuff:string;
BuffLen:integer;
begin
DataSetForReport[StationNum].TestingAbortedByTime:=true;
DataSetForReport[StationNum].PassTest:=true;
inc(PassedTestCount);
SendBuff:=Char (NM_EndOfTest)+Char (DataSetForReport[StationNum].Mark);
ZeroMemory (Addr(DataSetForReport[StationNum].Questions),254);
BuffLen:=Length(SendBuff);
ServerSocket1. Socket. Connections [DecodeNumToSocketNum(StationNum)].SendBuf(Pointer(SendBuff)^, BuffLen);
end;
procedure TServerForm. TableClear (Table:HLringGrid);
var i:word;
begin
for i:=1 to Table. RowCount do Table.Rows[i].Clear;
end;
procedure TServerForm. ReFillTable;
var i, ii:byte;
begin
DoAction:=false;
TableClear(StringGrid1);
i:=1;
if RegisteredClients>=StringGrid1.RowCount then StringGrid1. RowCount:=StringGrid1. RowCount+1;
for ii:=0 to 44 do
begin
if (DataSetForReport[ii].Registered)and (not DataSetForReport[ii].PassTest) then
begin
StringGrid1. Cells [0, i]:=DataSetForReport[ii].Ip;
StringGrid1. Cells [1, i]:=DataSetForReport[ii].Name;
StringGrid1. Cells [2, i]:=DataSetForReport[ii].Group;
StringGrid1. Cells [3, i]:=IntToStr (DataSetForReport[ii].True_+DataSetForReport[ii].False_);
StringGrid1. Cells [4, i]:=IntToStr (DataSetForReport[ii].True_);
StringGrid1. Cells [5, i]:=IntToStr (DataSetForReport[ii].False_);
StringGrid1. Cells [7, i]:=TimeToStr(DataSetForReport[ii].SumTime-DataSetForReport[ii].TimeLater);
StringGrid1. Cells [6, i]:=TimeToStr(DataSetForReport[ii].TimeLater);
StringGrid1. Cells [8, i]:='в процессе';
inc(i);
end;
end;
Label10. Caption:=IntToStr(PassedTestCount);
Label17. Caption:=IntToStr(NetworkErrors);
ConnectionCount. Caption:=inttostr(ConnectedSumm);
Label18. Caption:=IntToStr (RegisteredClients-PassedTestCount);
Label16. Caption:=IntToStr(RegisteredClients);
end;
procedure TServerForm. TimeRefresh;
var i, ii:byte;
begin
i:=1;
for ii:=0 to 44 do
begin
if (DataSetForReport[ii].Registered)and (not DataSetForReport[ii].PassTest) and (not DataSetForReport[ii].TestingAbortedByTime)then
begin
StringGrid1. Cells [6, i]:=TimeToStr(DataSetForReport[ii].TimeLater);
StringGrid1. Cells [7, i]:=TimeToStr(DataSetForReport[ii].SumTime-DataSetForReport[ii].TimeLater);
inc(i);
end;
end;
end;
procedure TServerForm. FormCreate (Sender:TObject);
var NewSearch:TSearchRec;
begin
QUESTIONBASE:=TQuestDB. Create(Handle);
USERSBASE:=TUsersDB. Create(Handle);
RootPath:=ExtractFilePath (Application.ExeName);
ShellTreeView1. Root:=RootPath+'Questions\';
StringGrid1. Cells [0,0]:='IP адрес';
StringGrid1. Cells [1,0]:='ФИО';
StringGrid1. Cells [2,0]:='Группа';
StringGrid1. Cells [3,0]:='Пройдено билетов';
StringGrid1. Cells [4,0]:='Верных';
StringGrid1. Cells [5,0]:='Неверных';
StringGrid1. Cells [6,0]:='Время тестирования';
StringGrid1. Cells [7,0]:='Осталось времени';
StringGrid1. Cells [8,0]:='Статус';
ReportGrid. Cells [0,0]:='ФИО';
ReportGrid. Cells [1,0]:='Группа';
ReportGrid. Cells [2,0]:='Дисциплина';
ReportGrid. Cells [3,0]:='Преподаватель';
ReportGrid. Cells [4,0]:='Верных';
ReportGrid. Cells [5,0]:='Неверных';
ReportGrid. Cells [6,0]:='Время';
ReportGrid. Cells [7,0]:='Оценка';
StringGrid2. Cells [0,0]:='IP адрес';
StringGrid2. Cells [1,0]:='ФИО';
StringGrid2. Cells [2,0]:='Дисциплина';
StringGrid2. Cells [3,0]:='Преподаватель';
StringGrid2. Cells [4,0]:='Пройдено';
StringGrid2. Cells [5,0]:='Верных';
StringGrid2. Cells [6,0]:='Неверных';
StringGrid2. Cells [7,0]:='Время';
GroupList:=USERSBASE. GetGroupsStringList;
FindFirst ('Groups\*.txt', faAnyfile,NewSearch);
repeat
Delete (NewSearch. Name, Length (NewSearch.Name) – 3,4);
ComboBox1. Items. Add (ExtractFileName(NewSearch.Name));
until FindNext(NewSearch)0;
if GroupList='' then ShowMessage ('Нет списков групп сервер незапущен')else ServerSocket1. Active:=true;
FindClose(NewSearch);
end;
procedure TServerForm. FormDestroy (Sender:TObject);
begin
ServerSocket1. Close;
ServerSocket1. Active:=false;
QUESTIONBASE. Destroy;
USERSBASE. Destroy;
end;
////////////////
procedure TServerForm. Timer1Timer (Sender:TObject);
var StationNum:byte;
begin
if (ConnectedSumm >0) or(StringGrid1. Cells [0,1]'') then
begin
if SecCounter>5 then
begin
DoAction:=true;
SecCounter:=0;
end else inc(SecCounter);
if RegisteredClients>0 then
for StationNum:=44 downto 0 do
if(DataSetForReport[StationNum].Registered) and (notDataSetForReport[StationNum].PassTest) and (not DataSetForReport[StationNum].TestingAbortedByTime)then
begin
DataSetForReport[StationNum].TimeLater:=DataSetForReport[StationNum].TimeLater+StrToTime('0:00:01');
ifDataSetForReport[StationNum].TimeLater>=DataSetForReport[StationNum].SumTimethen TimeOUTTesting(StationNum);
end;
if DoAction then
begin
ReFillTable;
FillReportTable;
end else TimeRefresh;
end elseConnectionCount.caption:=inttostr(ConnectedSumm);
end;
procedure TServerForm. ProblemWithData(From_:PCustomWinSocket; TxtMessage:string);
var SendBuf:string;
BuffLen:byte;
begin
SendBuf:=Char (NM_DataError);
SendBuf:=SendBuf+Char (Length(TxtMessage))+TxtMessage;
BuffLen:=Length(SendBuf);
From_.SendBuf (Pointer(SendBuf)^, BuffLen);
end;
procedure TServerForm. TestEvent (StationNum:byte;Socket_:PCustomWinSocket);
var CurrenHLation: Peoples;
WorkPath:string;
TmpStr: String;
SumCount: Byte;
RNDQuestNum: Word;
TrueAnsw: Word;
begin
CurrenHLation:=DataSetForReport[StationNum];
WorkPath:=DataSetForReport[StationNum].WorkPath;
SumCount:=DataSetForReport[StationNum].QuestCount;
randomize;
if DataSetForReport[StationNum].PassedCount
begin
QUESTIONBASE. TransactionUser:=DataSetForReport[StationNum].Ip+''+DataSetForReport[StationNum].Name+' '+DataSetForReport[StationNum].Group;
repeat
RNDQuestNum:=random(SumCount)+1; //Случайный номер вопроса
until notDataSetForReport[StationNum].Questions[RNDQuestNum].Passed;
if QUESTIONBASE. SetActiveWork (DataSetForReport[StationNum].UserWorkPathID.WorkID) then
if QUESTIONBASE. SetActiveTeacher (DataSetForReport[StationNum].UserWorkPathID.TeacherID) then
begin
TmpStr:=QUESTIONBASE. GetRandomFileBuilet(RNDQuestNum);
if TmpStr'' then // Случайныйбилет
// Найти верный ответ и послать по сети
begin
TrueAnsw:=QUESTIONBASE. GetTrueAnswerForBuilet(TmpStr);
// |–Вычисляем номер сокета клиента
// \/
SendQuestion (DecodeNumToSocketNum(StationNum),TmpStr, 0, TrueAnsw);
DataSetForReport[StationNum].OpenQuest:=RNDQuestNum;
DataSetForReport[StationNum].Questions[RNDQuestNum].Style:=0;
DataSetForReport[StationNum].Questions[RNDQuestNum].Passed:=False;
DataSetForReport[StationNum].Questions[RNDQuestNum].TrueAnswer:=TrueAnsw;
DataSetForReport[StationNum].Questions[RNDQuestNum].UserAnswer:=0;
end else ProblemWithData (Socket_, 'Errorwith Database');
end else ProblemWithData (Socket_, 'Errorwith Database');
end;
end;
//////////////////////
/////////////////////
////////////////////
procedure TServerForm. ComboBox1Change(Sender: TObject);
var fNames:textfile;
NameBuf:string;
NameCounter:byte;
begin
ListBox1. Clear;
AssignFile (fNames, 'Groups\'+ComboBox1.Items [ComboBox1. ItemIndex]+'.txt');
{$i-}
Reset(fNames);
NameCounter:=0;
While not Eof(fNames) do
begin
Readln (fNames, NameBuf);
ListBox1. Items. Add (IntToStr(NameCounter)+''+NameBuf);
inc(NameCounter);
end;
Label5. Caption:=IntToStr(NameCounter);
CloseFile(fNames);
{$i+}
end;
procedure TServerForm. Timer2Timer (Sender:TObject);
begin
Panel2. Visible:=false;
Timer2. Enabled:=false;
end;
procedure TServerForm. StringGrid1DblClick(Sender: TObject);
var MPoint:TPoint;
begin
if StringGrid1. Cells [0, SelectedRow]''then
begin
GetCursorPos(MPoint);
MPoint:=ScreenToClient(MPoint);
Label31. Caption:=DataSetForReport [SelectedRow-1].WorkName;
Label32. Caption:=DataSetForReport [SelectedRow-1].Teacher;
panel2. Top:=MPoint.Y;
panel2. Left:=MPoint.X;
panel2. Visible:=true;
timer2. Enabled:=True;
end;
end;
procedure TServerForm. Button3Click (Sender:TObject);
var ExtNameLen:byte;
NumName:string;
NumN: Word;
StrCQFile:string;
TrueAsw:byte;
begin
if not Panel3.visible then
begin
ExtNameLen:=Length (ExtractFileExt(CurrentQuestFile));
NumName:=ExtractFileName(CurrentQuestFile);
Delete (NumName, Length(NumName) –ExtNameLen+1, ExtNameLen);
try
CurrentQuestionNum:=StrToInt(NumName);
TrueAsw:=QUESTIONBASE. GetTrueAnswerForBuilet(CurrentQuestFile);
RadioGroup1. ItemIndex:=TrueAsw-1;
RadioGroup1. Show;
except
ShowMessage ('Это не файл билета');
exit;
end;
Image1. Picture. Bitmap. LoadFromFile(CurrentQuestFile);
Panel3.visible:=true;
Button3. Caption:='Закрыть';
end else
begin
Panel3.visible:=false;
RadioGroup1. Visible:=False;
Button3. Caption:='Просмотреть билет';
RadioGroup1. Hide;
end;
end;
procedure TServerForm. ShellListView1Change(Sender: TObject;
Item: TListItem; Change:TItemChange);
begin
Button3.enabled:=false;
if ShellListView1. ItemIndex>=0then
begin
CurrentQuestFile:=ShellTreeView1. Path+'\'+PChar(ShellListView1. SelectedFolder. DisplayName);
if (AnsiUpperCase (ExtractFileExt(CurrentQuestFile))=AnsiUpperCase('.bmp')) or (AnsiUpperCase(ExtractFileExt(CurrentQuestFile))=AnsiUpperCase ('.jpg'))then Button3.enabled:=true;
end;
end;
procedure TServerForm. ShellListView1DblClick(Sender: TObject);
begin
Button3.enabled:=false;
if ShellListView1. ItemIndex>=0then
begin
CurrentQuestFile:=ShellTreeView1. Path+'\'+PChar(ShellListView1. SelectedFolder. DisplayName);
if AnsiUpperCase (ExtractFileExt(CurrentQuestFile))=AnsiUpperCase('.bmp') then
begin
Button3.enabled:=true;
Button3. Click;
end;
end;
end;
procedure TServerForm. Image1Click (Sender:TObject);
begin
Button3. Click;
end;
procedure TServerForm. ShellTreeView1Enter(Sender: TObject);
begin
Button3. Enabled:=false;
end;
procedure TServerForm. FillReportTable;
var i, ii:byte;
begin
i:=1; // начинаем со второй строки
TableClear(ReportGrid);
if PassedTestCount>0 then
begin
for ii:=0 to 44 do
begin
if (DataSetForReport[ii].PassTest)then
begin
ReportGrid. Cells [0, i]:=DataSetForReport[ii].Name;
ReportGrid. Cells [1, i]:=DataSetForReport[ii].Group;
ReportGrid. Cells [2, i]:=DataSetForReport[ii].WorkName;
ReportGrid. Cells [3, i]:=DataSetForReport[ii].Teacher;
ReportGrid. Cells [4, i]:=IntToStr (DataSetForReport[ii].True_);
ReportGrid. Cells [5, i]:=IntToStr (DataSetForReport[ii].False_);
ReportGrid. Cells [6, i]:=TimeToStr (DataSetForReport[ii].TimeLater);
ReportGrid. Cells [7, i]:=IntToStr (DataSetForReport[ii].Mark);
inc(i);
end;
ReportGrid. RowCount:=i+2;
end;
end else ShowMessage ('Нет прошедших тестирование');
end;
procedure TServerForm. DisconnectComboBoxUpdate;
var i:integer;
begin
ComboBox2. Clear;
for i:=0 to 44 do
begin
if DataSetForReport[i].Registeredthen ComboBox2. Items. Add (DataSetForReport[i].Name);
end;
end;
procedure TServerForm. CreateReport;
var
RangeW:word2000.range;
j:integer;
StrArr:array of string[30];
Data: WideString;
SData:string;
Sep, tmpRange, NumCols: OleVariant;
Parfs: Paragraphs;
Par: Paragraph;
begin
WordDocument1. Activate;
WordDocument1. Range. Font. Bold:=0;
WordDocument1. Range. Font. Size:=14;
WordDocument1. PageSetup. LeftMargin:=20;
WordDocument1. PageSetup. TopMargin:=20;
WordDocument1. PageSetup. RightMargin:=20;
WordDocument1. PageSetup. BottomMargin:=60;
SetLength (StrArr, ReportGrid. RowCount);
RangeW:=WordDocument1. Range (emptyParam,emptyParam);
tmpRange:=RangeW;
Parfs:=WordDocument1. Paragraphs;
par:=Parfs. Add(tmpRange);
tmpRange:=Par. Range.get_end_;
RangeW:=WordDocument1. Range(tmpRange);
SData:='';
Data:='ФИО@Группа@Дисциплина@Верных@Неверных@Время@Оценка@';
for j:=1 to ReportGrid. RowCount do
begin
begin // вывод информации по одномупреподавателю
SData:=SData+ReportGrid. Cells [0, j]+'@'+ReportGrid.Cells [1, j]+'@'+ReportGrid. Cells [2, j]+'@'
+ReportGrid. Cells [4, j]+'@'+ReportGrid.Cells [5, j]+'@'+ReportGrid. Cells [6, j]+'@'+
ReportGrid. Cells [7, j]+'@';
Data:=Data+SData;
SData:='';
end;
end;
tmpRange:=RangeW;
Par:=Parfs. Add(tmpRange);
Par. Range. InsertBefore(Data);
Sep:='@';
NumCols:=7;
RangeW. ConvertToTableOld (Sep, EmptyParam,NumCols, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam);
WordDocument1. Disconnect;
SetLength (StrArr, 0);
end;
procedure TServerForm. Button1Click (Sender:TObject);
var
MsWord: Variant;
begin
try
MsWord:= CreateOleObject ('Word. Application');
MsWord. Visible:= True;
MsWord. Caption:='Отчет по реультатам тестирования';
CreateReport;
except
ShowMessage ('Невозможно запуститьMicrosoft Word');
Exit;
end;
end;
procedure TServerForm. SpeedButton1Click(Sender: TObject);
var Command:byte;
begin
if ComboBox2. ItemIndex>=0 then
begin
Command:=NM_KickFromServer;
ServerSocket1. Socket. Connections [ComboBox2.ItemIndex].SendBuf (Command, 1);
end;
end;
procedure TServerForm. StringGrid1SelectCell(Sender: TObject; ACol,
ARow: Integer; var CanSelect:Boolean);
begin
SelectedRow:=ARow;
end;
procedure TServerForm. Button7Click (Sender:TObject);
begin
Memo1. Clear;
end;
procedure TServerForm. Button8Click (Sender:TObject);
begin
if SaveDialog1. Execute then Memo1. Lines.SaveToFile (SaveDialog1. FileName);
end;
procedure TServerForm. LogMessage (varMessage: TMessage);
begin
Memo1. Lines. Add (DateTimeToStr(Now)+''+PChar (Message.WParam));
end;
end.
unit QBaseWork;
interface
uses
Windows, Messages, SysUtils,Classes, Dialogs, IniFiles;
const
ErrWorkListLoad = 1;
ErrImputWorkNumberFault = 2;
ErrTeachersListLoad = 3;
ErrImputTeacherNumberFault = 4;
ErrQuestionsNotFound = 5;
ErrConfigIniFileWorkSetNotFound = 6;
ErrReadBuiletNumber = 7;
ErrQuestionWithInputedNumberNotFound= 8;
ErrQuestionFileWithInputedNumberNotFound= 9;
ErrInSelectedDirectoryNotQuestFileNameFound= 10;
ErrGenerationRndQuest = 11;
type
DBase=record
Works:HLringList;
Teachers:array of HLringList;
end;
type
TQuestDB = class
private
SelfParent:HWND;
NewBase:DBase;
WorksCount_:integer;
WorkTimeLimit_:String;
ProgRootDir:string;
ActiveWork:string;
ActiveTeacher:string;
ActiveWorkNum:byte;
ActiveTeacherNum:byte;
///////QUESTIONS /////////
ImgType:string;
QuestCount:integer;
QuestionsPathName:string;
ActivTransactionUser: String;
procedureERROR_MESSAGE_FOR_DEBUG_LEVEL (ErrID:byte);
///////QUESTIONS /////////
function ConverHLrToIntNum (StringNum:string): integer;
function TestByDigit (DataString:string): boolean;
procedure SMessage (Message_:string);
function UpdateQuestionsSet:boolean;
// function GetWorkIndex (WorkName:string): integer;
// function GetTeacherIndex (TeacherName:string): integer;
public
constructor Create (ParentHwnd:HWND);
destructor Destroy; override;
function SetActiveTeacher (Num:byte):boolean;
function SetActiveWork (Num:byte):boolean;
function GetWorksStringList:string;
functionGetTeachersStringList:string;
property ActivWorkName:string readActiveWork;
property ActivTeacherName:stringread ActiveTeacher;
property TransactionUser:string readActivTransactionUser write ActivTransactionUser;
property PubActivWorkNum:byte readActiveWorkNum;
property PubActivTeacherNum:byteread ActiveTeacherNum;
property QuestionsFullPath:stringread QuestionsPathName;
function GetWorkByIndex (i: byte):string;
function GetTeacherByIndex (i:byte): string;
///////QUESTIONS /////////
property ImgFileType:string readImgType;
property QuestionsCount:integer readQuestCount;
property WorkTimeLimit: String readWorkTimeLimit_;
function GetBuiletByNum (Num:integer): string;
function GetFileBuiletByNumBuilet (BuiletNum,FileNum: integer): string;
function GetRandomFileBuilet (BuiletNum:integer): string;
function GetTrueAnswerForBuilet (QuestionPath:string): integer;
function SetTrueAnswerForBuilet (QuestionPath:string; TrueAnswer: Integer): boolean;
end;
implementation
{TQuestDB}
constructor TQuestDB. Create (ParentHwnd:HWND);
var ExeName:PChar;
AppName: String;
ExeNameLen:byte;
/////
NewSearch_:TSearchRec;
i, ii:byte;
QuestionPathName:string;
QCount:integer;
FOptions:TIniFile;
begin
SelfParent:=ParentHwnd;
GetMem (ExeName, 255);
ExeNameLen:=255;
GetModuleFileName (0, ExeName, ExeNameLen); //определяем имя исполняемого модуля
AppName:=StrPas(ExeName);
ProgRootDir:=ExtractFileDir(AppName);
WorksCount_:=0;
NewBase. Works:=HLringList. Create; //заполняем список работ
FindFirst (ProgRootDir+'\Questions\*',faDirectory, NewSearch_);
repeat
if NewSearch_.Name[1]'.'then
begin
NewBase. Works. Add (NewSearch_.Name);
inc (WorksCount_);
end;
until FindNext (NewSearch_)0;
FindClose (NewSearch_);
// Заполняем списки преподов
SetLength (NewBase. Teachers, WorksCount_);
for i:=0 to WorksCount_-1 do
begin
NewBase. Teachers[i]:=HLringList. Create;
FindFirst (ProgRootDir+'\Questions\'+NewBase.Works. Strings[i]+'\*', faDirectory, NewSearch_);
repeat
if NewSearch_.Name[1]'.'then NewBase. Teachers[i].Add (NewSearch_.Name);
until FindNext (NewSearch_)0;
FindClose (NewSearch_);
end;
for i:=0 to NewBase. Works. Count-1do
begin
for ii:=0 to NewBase. Teachers[i].Count-1do
begin
QuestionPathName:=ProgRootDir+'\Questions\'+NewBase.Works. Strings[i]+'\'+ NewBase. Teachers[i].Strings[ii];
if FileExists (QuestionPathName+'\WorkSet.ini')then
begin
FOptions:=TIniFile. Create (QuestionPathName+'\WorkSet.ini');
QCount:=0;
FindFirst (QuestionPathName+'\*', faDirectory,NewSearch_);
repeat
if NewSearch_.Name[1]'.'then
if TestByDigit (NewSearch_.Name)then inc(QCount);
until FindNext (NewSearch_)0;
FindClose (NewSearch_);
FOptions. WriteInteger ('QuestionCount','value', QCount);
FOptions. Free;
if QCount>0 thenQuestCount:=QCount else ERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrQuestionsNotFound);
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrConfigIniFileWorkSetNotFound);
end;
end;
end;
destructor TQuestDB. Destroy;
var i:integer;
begin
for i:=0 to NewBase. Works. Count-1do
begin
NewBase. Teachers[i].Destroy;
end;
SetLength (NewBase. Teachers, 0);
NewBase. Works. Destroy;
inherited;
end;
function TQuestDB. SetActiveWork (Num:byte):boolean;
begin
result:=false;
if Num
begin
ActiveWork:=NewBase. Works. Strings[Num];
ActiveWorkNum:=Num;
result:=true;
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrImputWorkNumberFault);
end;
function TQuestDB. SetActiveTeacher (Num:byte):boolean;
begin
result:=false;
if Num
begin
ActiveTeacher:=NewBase. Teachers[ActiveWorkNum].Strings[Num];
ActiveTeacherNum:=Num;
if UpdateQuestionsSet thenresult:=true;
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrImputTeacherNumberFault);
end;
function TQuestDB. GetTeachersStringList:string;
var i:integer;
begin
Result:='';
for i:=0 to NewBase. Teachers[ActiveWorkNum].Count-1do Result:=Result+NewBase. Teachers[ActiveWorkNum].Strings[i]+'|';
Result:=Result+'>';
end;
function TQuestDB. GetWorksStringList:string;
var i:integer;
begin
Result:='';
for i:=0 to NewBase. Works. Count-1do Result:=Result+NewBase. Works. Strings[i]+'|';
Result:=Result+'>';
end;
function TQuestDB. GetWorkByIndex (i:byte):string;
begin
if i
end;
function TQuestDB. GetTeacherByIndex(i:byte): string;
begin
if i
Result:=NewBase. Teachers[ActiveWorkNum].Strings[i]else
Result:='';
end;
procedureTQuestDB.ERROR_MESSAGE_FOR_DEBUG_LEVEL (ErrID: byte);
begin
Case ErrID of
ErrWorkListLoad:
begin
SMessage ('Base read works error');
end;
ErrTeachersListLoad:
begin
SMessage ('Base read teacherserror');
end;
ErrImputWorkNumberFault:
SMessage ('Imput work numberfault');
ErrImputTeacherNumberFault:
SMessage ('Imput work numberfault');
ErrQuestionsNotFound:
SMessage ('No questions found inbase');
ErrConfigIniFileWorkSetNotFound:
SMessage ('Config file WorkSet.ininot found');
ErrReadBuiletNumber:
SMessage ('Error with read number ofbuilet');
ErrQuestionWithInputedNumberNotFound:
SMessage ('Direstory with inputednumber (QuestionNum) is not found (number out of range)');
ErrQuestionFileWithInputedNumberNotFound:
SMessage ('File with inputed number(QuestionName) is not found (number out of range)');
ErrInSelectedDirectoryNotQuestFileNameFound:
SMessage ('In the selected tirectoryquestion file is not found');
ErrGenerationRndQuest:
SMessage ('Error by generationrandom question file maybe question directory is not found');
ErrInvalidFileNameTraslate:
SMessage ('Invalid Translatequestion name filename STR to INT maybe filename error');
end;
end;
Procedure TQuestDB.SMessage (Message_:string);
begin
SendMessage (SelfParent, WM_User+2, DWord(PChar(TransactionUser+' '+Message_)), 0);
end;
/////////////////QUESTIONS ////////////////
function TQuestDB. UpdateQuestionsSet:boolean;
var QCount:integer;
EnumFileDir:TSearchRec;
FOptions:TIniFile;
TryConvert:TDateTime;
WorkTimeLim:string;
begin
QuestionsPathName:=ProgRootDir+'\Questions\'+ActiveWork+'\'+ActiveTeacher;
try
try
FOptions:=TIniFile. Create (QuestionsPathName+'\WorkSet.ini');
QuestCount:=FOptions. ReadInteger ('QuestionCount','value', – 1);
WorkTimeLim:=FOptions. ReadString ('TimeForWork','value', '0:00:00');
TryConvert:=StrToTime(WorkTimeLim);
WorkTimeLimit_:=WorkTimeLim;
ImgType:=FOptions. ReadString ('ImgType','value', 'bmp');
FOptions. Destroy;
finally
if QuestCount>0 then result:=trueelse result:=false;
end;
except
result:=false;
end;
end;
function TQuestDB. ConverHLrToIntNum(StringNum:string):integer;
var ProtectAssign:integer;
begin
if TestByDigit(StringNum) then
begin
ProtectAssign:=StrToInt(StringNum);
result:=ProtectAssign;
end else
begin
ERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrReadBuiletNumber);
result:=-1;
end;
end;
function TQuestDB. TestByDigit (DataString:string):boolean;
var DataLen:byte;
Offs:byte;
begin
Result:=true;
DataLen:=Length(DataString);
for Offs:=1 to DataLen do
if not (DataString[Offs] in['0'..'9']) then
begin
result:=false;
break;
end;
end;
function TQuestDB. GetBuiletByNum (Num:integer):string;
var EnumBuiletsFile:TSearchRec;
StringBuiletNum:string;
begin
Result:='';
FindFirst (QuestionsPathName+'\*', faDirectory,EnumBuiletsFile);
repeat
if EnumBuiletsFile. Name[1]'.'then
begin
StringBuiletNum:=EnumBuiletsFile. Name;
if TestByDigit(StringBuiletNum) then
if ConverHLrToIntNum(StringBuiletNum)=Numthen
begin
result:=QuestionsPathName+'\'+EnumBuiletsFile.Name;
break;
end;
end;
untilFindNext(EnumBuiletsFile)0;
FindClose(EnumBuiletsFile);
If Result='' thenERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrQuestionWithInputedNumberNotFound);
end;
function TQuestDB. GetFileBuiletByNumBuilet(BuiletNum, FileNum:integer):string;
var EnumBuiletsNamesFile:TSearchRec;
StringBuiletNum:string;
begin
Result:='';
FindFirst (QuestionsPathName+'\'+IntToStr(BuiletNum)+'\*',faAnyFile, EnumBuiletsNamesFile);
repeat
if EnumBuiletsNamesFile. Name[1]'.'then
begin
StringBuiletNum:=EnumBuiletsNamesFile.Name;
Delete (StringBuiletNum, Length(StringBuiletNum) –3,4);
if TestByDigit(StringBuiletNum) then
if ConverHLrToIntNum(StringBuiletNum)=FileNumthen
begin
result:=QuestionsPathName+'\'+EnumBuiletsNamesFile.Name;
break;
end;
end;
untilFindNext(EnumBuiletsNamesFile)0;
FindClose(EnumBuiletsNamesFile);
If Result='' thenERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrQuestionFileWithInputedNumberNotFound);
end;
function TQuestDB. GetRandomFileBuilet(BuiletNum:integer):string;
var EnumBuiletsNamesFile:TSearchRec;
RndCount:integer;
FileList:HLringList;
WorkPath:string;
begin
Result:='';
FileList:=HLringList. Create;
FileList. Clear;
WorkPath:=QuestionsPathName+'\'+IntToStr(BuiletNum);
if DirectoryExists(WorkPath) then
begin
FindFirst (WorkPath+'\*', faAnyFile,EnumBuiletsNamesFile);
repeat
if EnumBuiletsNamesFile. Name[1]'.'then
FileList. Add (EnumBuiletsNamesFile.Name);
untilFindNext(EnumBuiletsNamesFile)0;
FindClose(EnumBuiletsNamesFile);
if FileList. Count>0 then
begin
Randomize;
RndCount:=Random (FileList. Count);
Result:=QuestionsPathName+'\'+IntToStr(BuiletNum)+'\'+FileList.Strings[RndCount];
end;
end;
FileList. Destroy;
If Result='' thenERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrGenerationRndQuest);
end;
function TQuestDB. GetTrueAnswerForBuilet(QuestionPath:string):integer;
var QuestNum:integer;
TmpStr:string;
KeyFilePath:string;
TempQuestionsList:HLringList;
begin
Result:=-1;
QuestNum:=0;
TmpStr:=ExtractFileName(QuestionPath);
Delete (TmpStr, Length(TmpStr) –Length (ExtractFileExt(TmpStr))+1, Length (ExtractFileExt(TmpStr)));
if (TestByDigit(TmpStr)) and(Length(TmpStr)
begin
QuestNum:=StrToInt(TmpStr);
end else
begin
ERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrInvalidFileNameTraslate);
Result:=-1;
exit;
end;
KeyFilePath:=ExtractFilePath (ExtractFileDir(QuestionPath))+'QuestKey.ini';
if FileExists(KeyFilePath) then
begin
TempQuestionsList:=HLringList. Create;
TempQuestionsList. LoadFromFile(KeyFilePath);
Result:=StrToInt (TempQuestionsList.Strings[QuestNum]);
TempQuestionsList. Destroy;
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrConfigIniFileWorkSetNotFound);
end;
function TQuestDB. SetTrueAnswerForBuilet(QuestionPath:string; TrueAnswer: Integer):boolean;
var QuestNum:integer;
TmpStr:string;
KeyFilePath:string;
TempQuestionsList:HLringList;
begin
Result:=false;
QuestNum:=0;
TmpStr:=ExtractFileName(QuestionPath);
Delete (TmpStr, Length(TmpStr) –Length (ExtractFileExt(TmpStr))+1, Length (ExtractFileExt(TmpStr)));
if (TestByDigit(TmpStr)) and(Length(TmpStr)
begin
QuestNum:=StrToInt(TmpStr);
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrInvalidFileNameTraslate);
KeyFilePath:=ExtractFilePath (ExtractFileDir(QuestionPath))+'QuestKey.ini';
if FileExists(KeyFilePath) then
begin
TempQuestionsList:=HLringList. Create;
TempQuestionsList. LoadFromFile(KeyFilePath);
TempQuestionsList. Strings[QuestNum]:=IntToStr(TrueAnswer);
TempQuestionsList. SaveToFile (KeyFilePath+'_');
TempQuestionsList. Destroy;
DeleteFile(KeyFilePath);
RenameFile (KeyFilePath+'_', KeyFilePath);
Result:=true;
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrConfigIniFileWorkSetNotFound);
end;
end.
unit UBaseWork;
interface
uses Windows, Messages, SysUtils,Classes, Dialogs, IniFiles;
const
ErrImputGroupNumberFault = 1;
ErrImputUserNumberFault = 2;
type
UsersDBase=record
Groups:HLringList;
Users:array of HLringList;
end;
type
TUsersDB = class
private
SelfParent:HWND;
UsersDataBase: UsersDBase;
GroupsCount:integer;
ProgRootDir:string;
ActiveGroup:string;
ActiveUser:string;
ActivStationIP:string;
ActiveGroupNum:byte;
ActiveUserNum:byte;
procedureERROR_MESSAGE_FOR_DEBUG_LEVEL (ErrID: byte);
procedure SMessage (Message_:string);
public
property TransactionIP:string readActivStationIP write ActivStationIP;
property ActiveUserName:string readActiveUser;
property ActiveGroupName:string readActiveGroup;
function SetActiveGroup (Num: byte):boolean;
function SetActiveUser (Num: byte):boolean;
function GetGroupByIndex (i: byte):string;
function GetUserByIndex (i: byte):string;
function GetGroupsStringList:string;
function GetUsersStringList: string;
constructor Create (ParentHwnd:HWND);
destructor Destroy; override;
end;
implementation
{TQuestDB}
constructor TUsersDB. Create (ParentHwnd:HWND);
var ExeName:PChar;
AppName: String;
ExeNameLen:byte;
/////
NewSearch_:TSearchRec;
CleanName:string;
i:byte;
begin
SelfParent:=ParentHwnd;
GetMem (ExeName, 255);
ExeNameLen:=255;
GetModuleFileName (0, ExeName, ExeNameLen); //определяем имя исполняемого модуля
AppName:=StrPas(ExeName);
ProgRootDir:=ExtractFileDir(AppName);
GroupsCount:=0;
UsersDataBase. Groups:=HLringList. Create;
FindFirst (ProgRootDir+'\Groups\*', faDirectory,NewSearch_);
repeat
if NewSearch_.Name[1]'.'then
begin
UsersDataBase. Groups. Add (NewSearch_.Name);
inc(GroupsCount);
end;
until FindNext (NewSearch_)0;
FindClose (NewSearch_);
SetLength (UsersDataBase. Users, GroupsCount);
for i:=0 to GroupsCount-1 do
begin
UsersDataBase. Users[i]:=HLringList.Create;
UsersDataBase. Users[i].LoadFromFile(ProgRootDir+'\Groups\'+UsersDataBase. Groups. Strings[i]);
CleanName:=UsersDataBase. Groups. Strings[i];
Delete (CleanName, Length(CleanName) –3,4);
UsersDataBase. Groups. Strings[i]:=CleanName;
end;
end;
destructor TUsersDB. Destroy;
var i:integer;
begin
for i:=0 to UsersDataBase. Groups. Count-1do
begin
UsersDataBase. Users[i].Destroy;
end;
SetLength (UsersDataBase. Users, 0);
UsersDataBase. Groups. Destroy;
inherited;
end;
function TUsersDB. SetActiveGroup (Num:byte):boolean;
begin
result:=false;
if Num
begin
ActiveGroup:=UsersDataBase. Groups. Strings[Num];
ActiveGroupNum:=Num;
result:=true;
end elseERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrImputGroupNumberFault);
end;
function TUsersDB. SetActiveUser (Num:byte):boolean;
begin
result:=false;
if Num
begin
ActiveUser:=UsersDataBase. Users[ActiveGroupNum].Strings[num];
ActiveUserNum:=Num;
result:=true;
end else ERROR_MESSAGE_FOR_DEBUG_LEVEL(ErrImputUserNumberFault);
end;
procedureTUsersDB.ERROR_MESSAGE_FOR_DEBUG_LEVEL (ErrID: byte);
begin
Case ErrID of
ErrImputGroupNumberFault:
SMessage ('Imput group numberfault');
ErrImputUserNumberFault:
SMessage ('Imput user numberfault');
end;
end;
Procedure TUsersDB.SMessage (Message_:string);
begin
SendMessage (SelfParent, WM_User+2, DWord(PChar(ActivStationIP+' '+Message_)), 0);
end;
function TUsersDB. GetGroupByIndex (i:byte):string;
begin
if i
end;
function TUsersDB. GetUserByIndex (i:byte):string;
begin
if i
Result:=UsersDataBase. Users[ActiveGroupNum].Strings[i]else Result:='';
end;
function TUsersDB. GetGroupsStringList:string;
var i:integer;
begin
Result:='';
for i:=0 to UsersDataBase. Groups. Count-1do Result:=Result+UsersDataBase. Groups. Strings[i]+'|';
Result:=Result+'>';
end;
function TUsersDB. GetUsersStringList:string;
var i:integer;
begin
Result:='';
for i:=0 to UsersDataBase. Users[ActiveGroupNum].Count-1do Result:=Result+UsersDataBase. Users[ActiveGroupNum].Strings[i]+'|';
Result:=Result+'>';
end;
end.
/>/>Приложение2Листинг кодаклиентской части программы
unit Registation;
interface
uses
Windows, Messages, SysUtils,Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
HLartForm = class(TForm)
Panel2: TPanel;
ComboBox3: TComboBox;
ComboBox4: TComboBox;
Label5: TLabel;
Label6: TLabel;
Bevel2: TBevel;
Bevel3: TBevel;
Panel1: TPanel;
Bevel4: TBevel;
Bevel5: TBevel;
Label3: TLabel;
Label4: TLabel;
ComboBox1: TComboBox;
ComboBox2: TComboBox;
Bevel6: TBevel;
Bevel7: TBevel;
Panel3: TPanel;
Bevel1: TBevel;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Panel4: TPanel;
procedure ComboBox1Change (Sender:TObject);
procedure Button2Click (Sender:TObject);
procedure Button1Click (Sender:TObject);
procedure Button3Click (Sender:TObject);
procedure ComboBox3Change (Sender:TObject);
procedure ComboBox2Change (Sender:TObject);
procedure FormClose (Sender:TObject; var Action: TCloseAction);
private
ServerIPAddress:string[15]; //IPадрес
Steps:byte; // номер шага регистрации (условно)
NoModify:boolean; // триггер интерфейса
function ReadServerIP: string; //чтение из файла IP.DAT информации о IP адресе сервера
public
procedure GetConnect; // Установка соединение
procedure HideWin_(YN: boolean); //скрыть элементы управленияWindows (TaskBar, Deskdop)
procedure ExitProgram;
end;
var
StartForm: HLartForm;
implementation
uses MainForm;
{ /////////////////////////////////////////////////////
BEGIN
Сервисные подпрограммы
//////////////////////////////////////////////////////}
function HLartForm. ReadServerIP:string;
var IPInfFile:textfile;
IP:string;
begin
if fileexists (extractfilepath(application.ExeName)+'IP. Dat') then
begin
assignfile (IPInfFile, extractfilepath(application. ExeName)+'IP. Dat');
{$i-}
reset(IPInfFile);
Readln (IPInfFile, IP);
closefile(IPInfFile);
{$i+}
if ip'' then
begin
ReadServerIP:=IP;
end
else ReadServerIP:='127.0.0.1';
end else
begin
ReadServerIP:='127.0.0.1';
end;
end;
procedure HLartForm. HideWin_(YN:boolean);
var Wnd: hWnd;
ClassName:PChar;
ClassNameLen:byte;
Res:string;
begin
Wnd:=FindWindow ('Progman', 'ProgramManager');
while wnd0 do
begin
wnd:=GetWindow (Wnd, GW_CHILD);
ClassNameLen:=0;
GetClassName (Wnd, ClassName, ClassNameLen);
SeHLring (Res, ClassName, ClassNameLen);
SeHLring (Res, ClassName, StrLen(ClassName));
if Res='SysListView32' then
begin
if YN=true then
begin
ShowWindow (Wnd, SW_Hide);
ShowWindow (findwINDOW('Shell_TrayWnd',nil), SW_Hide);
end else
begin
ShowWindow (Wnd, SW_Show);
ShowWindow (findwINDOW('Shell_TrayWnd',nil), SW_Show);
end;
break;
end;
end;
FreeMem (ClassName, 255);
end;
procedure HLartForm. ExitProgram;
begin
HideWin_(false);
Application. ProcessMessages;
Application. Terminate;
end;
{ /////////////////////////////////////////////////////
Сервисные подпрограммы
END
//////////////////////////////////////////////////////}
{ /////////////////////////////////////////////////////
BEGIN
Сетевые подпрограммы
////////////////////////////////////////////////////// }
procedure HLartForm. GetConnect;
begin
try
ServerIPAddress:=ReadServerIP;
TestForm. TestSocket. Address:=ServerIPAddress;
TestForm. TestSocket. Active:=true;
except
end;
end;
{ /////////////////////////////////////////////////////
Сетевые подпрограммы
END
//////////////////////////////////////////////////////}
{ /////////////////////////////////////////////////////
BEGIN
Обработка пользовательского интерфейса
//////////////////////////////////////////////////////}
procedure HLartForm. ComboBox1Change(Sender: TObject);
var Data:string;
begin
Data:=Char (NM_Register2)+Char (TestForm.MyNumber)+Char (ComboBox1. ItemIndex);
TestForm. TestSocket. Socket. SendBuf(Pointer(Data)^, Length(Data));
ComboBox3. Clear;
ComboBox4. Clear;
ComboBox2. Clear;
NoModify:=false;
Steps:=0;
end;
procedure HLartForm. Button2Click (Sender:TObject);
begin
Close;
end;
procedure HLartForm. Button1Click (Sender:TObject);
var Data:string;
begin
case Steps of // Дальнейшее действие
0:if ComboBox2. Text'' then
begin
NoModify:=true;
Data:=Char (NM_RegisterGetWorks)+Char(TestForm. MyNumber)+Char (ComboBox1. ItemIndex);
TestForm. TestSocket. Socket. SendBuf(Pointer(Data)^, Length(Data)); // Запрос на получение списка предметов
end;
Button3. Enabled:=true;
Panel1. Hide;
Panel2. Show; Steps:=1;
end;
1: if Panel2. Visible then
begin
if ComboBox4. Text'' then
begin
Data:=Char (NM_RegisterOK)+Char (TestForm.MyNumber)+
Char (ComboBox1. ItemIndex)+Char (ComboBox2.ItemIndex)+Char (ComboBox3. ItemIndex)+Char (ComboBox4. ItemIndex);
TestForm. TestSocket. Socket. SendBuf(Pointer(Data)^, Length(Data)); // Отсылка сведений для
// окончательной регистрации
Self.Hide;
HideWin_(true);
end;
end else
begin
Panel1. Hide;
Panel2. Show;
Button3. Enabled:=true;
Steps:=1;
end;
end;
end;
procedure HLartForm. Button3Click (Sender:TObject);
begin
Panel2. Hide;
Panel1. Show;
Button3. Enabled:=false;
end;
procedure HLartForm. ComboBox3Change(Sender: TObject);
var Data:string;
begin
uses
Windows, Messages, SysUtils,Variants, Classes, Graphics, Controls, Forms,
Dialogs, WinSock, ExtCtrls, Buttons,StdCtrls, ScktComp;
const
NM_Register1 = 6; // прием списка групп
NM_Register2 = 7; // запрос на списокстудентов
NM_RegisterGetWorks = 66; // запрос /ответ 'список предметов'
NM_RegisterGetTeachers = 77; // запрос /ответ 'список преподователей'
NM_RegisterOK = 8; // клиентзарегистрирован
NM_Service = 31; // прием сервиснойинформации
NM_TestEvent = 55; // событие по ходутестирования
NM_FileOperation = 10; // сетевая операцияс файлами
NM_EndOfTest = 33; // окончаниетестирования
NM_KickFromServer = 44; // отключение отсервера администратором
NM_Wait = 61;
NM_DataError = 54; // проблема с БД
procedure TTestForm. TestSocketRead (Sender:TObject;
Socket: TCustomWinSocket);
type TDataBuffer=array of byte; //буфер данных
var Data, Data1:string; // данные
SendLen:integer;
DataBuffer:TDataBuffer;
i: Word;
Command:byte;
GetSize:PInt64;
SizeOfFilename:byte;
PTrueAnswer:PWord;
PTimeForPassTest:PDouble;
begin
SendLen:=Socket. ReceiveLength; //размер принятых данных
SetLength (DataBuffer, SendLen);
Socket. ReceiveBuf (Pointer(DataBuffer)^,SendLen); // заполняем буфер
if lock then // если в режиме приема файлато продолжить прием
begin
MakePointer:=DWORD(DataBuffer);
NewFile. WriteBuffer (Pointer(MakePointer)^,SendLen);
SendedSize:=SendedSize+SendLen;
if SendedSize=FileSize then // если приняли весь файл то выход
begin
lock:=false;
NewFile. Destroy;
SetImg(FileName);
end;
end else
begin
Command:=DataBuffer[0];
case Command of
NM_Register1:
begin
MyNumber:=DataBuffer[1];
i:=2;
while i
begin
Data:='';
while DataBuffer[i]byte ('|')do
begin
Data:=Data+Char (DataBuffer[i]);
inc(i);
end;
if Data'' then StartForm. ComboBox1.Items. Add(Data);
if DataBuffer [i+1]=byte ('>')then break;
inc(i);
end;
end;
NM_Register2: // список студентов
begin
i:=1;
while i
begin
Data:='';
while DataBuffer[i]byte ('|')do
begin
Data:=Data+Char (DataBuffer[i]);
inc(i);
end;
if Data'' then StartForm. ComboBox2.Items. Add(Data);
if DataBuffer [i+1]=byte ('>')then break;
inc(i);
end;
end;
NM_RegisterGetWorks:
begin
i:=1;
StartForm. ComboBox3. Clear;
while i
begin
Data:='';
while DataBuffer[i]byte ('|')do
begin
Data:=Data+Char (DataBuffer[i]);
inc(i);
end;
if Data'' then StartForm. ComboBox3.Items. Add(Data);
if DataBuffer [i+1]=byte ('>')then break;
inc(i);
end;
end;
NM_RegisterGetTeachers:
begin
StartForm. ComboBox4. Clear;
i:=1;
while i
begin
Data:='';
while DataBuffer[i]byte ('|')do
begin
Data:=Data+Char (DataBuffer[i]);
inc(i);
end;
if Data'' then StartForm. ComboBox4.Items. Add(Data);
if DataBuffer [i+1]=byte ('>')then break;
inc(i);
end;
end;
NM_FileOperation:
begin
lock:=true;
PTrueAnswer:=Addr (DataBuffer[1]);
TrueAnswer:=PTrueAnswer^;
QuestionStyle:=DataBuffer[3];
GetSize:=Addr (DataBuffer[4]);
FileSize:=GetSize^;
SizeOfFilename:=DataBuffer[12];
Filename:=ApplicationPath+'Data.tmp'; //имя передаваемого файла
Deletefile(FileName);
NewFile:=TFileStream. Create (FileName,fmCreate);
NewFile. Position:=0;
MakePointer:=DWORD(DataBuffer)+13+SizeOfFilename; //13=1+1+1+1+8+1
NewFile. WriteBuffer (Pointer(MakePointer)^,SendLen-13-SizeOfFilename);
SendedSize:=SendLen-13-SizeOfFilename;
if SendedSize=FileSize then // если приняли весь файл то выход
begin
lock:=false;
NewFile. Destroy;
SetImg(FileName);
end;
end;
NM_EndOfTest:
begin
SpeedButton5. Enabled:=false;
TestPassed:=true;
Mark:=DataBuffer[1];
PostMessage (Handle, WM_User, 0,0);
end;
NM_KickFromServer:
begin
TestTerminated:=true;
Label7. Hide;
Label8. Hide;
Button2. Hide;
Panel7. Caption:='Тестирование прервано';
PostMessage (Handle, WM_User, 0,0);
end;
NM_Service:
begin
QuestionsCount:=DataBuffer[1];
PTimeForPassTest:=Addr (DataBuffer[2]);
TimeForPassTest:=TTime (PTimeForPassTest^);
end;
NM_DataError:
begin
SendLen:=DataBuffer[1];
Data1:=Copy (PChar(DataBuffer), 3, SendLen)+#13+#10+#0;
PostMessage (Handle, WM_User+1, DWORD(PChar(Data1)), 1);
end;
NM_Wait: ShowMessage('Wait');
end;
end;
SetLength (DataBuffer, 0);
end;
procedure TTestForm. CloseNetworkSocket(var Message: TMessage);
begin
TestSocket. Active:=false;
TestSocket.close;
if TestForm. Visible then
begin
Panel8. Hide;
Panel7. Top:=Panel8. Top;
Panel7. Left:=Panel8. Left;
Panel7. Width:=Panel8. Width;
Panel7. Height:=Panel8. Height;
Panel7. Visible:=true;
if TestPassed then Panel7. Caption:=IntToStr(Mark)else
begin
Application. ProcessMessages;
Sleep(4000);
Application. ProcessMessages;
Application. Terminate;
end;
end else // если окно теста не открыто
begin
StartForm. Panel4. Visible:=true;
Application. ProcessMessages;
Sleep(4000);
Application. ProcessMessages;
Application. Terminate;
end;
end;
procedure TTestForm. TestSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
if not (TestPassed orTestTerminated) then Application. Terminate;
end;
{ /////////////////////////////////////////////////////
Сетевые подпрограммы
END
//////////////////////////////////////////////////////}
end;
end.
/>/>Литература
1. АрхангельскийА.Я. Delphi 7 Справочное пособие. – М., Бином-Пресс. -2004. -1024 с.
2. АрхангельскийА.Я. Программирование в Delphi 7 + дискета, Бином, 2005
3. БондаренкоЕ.А. Технические средства обучения в современной школе, Юверс, 2004
4. ВигерсКарл. Разработка требований к программному обеспечению. /Пер, с англ. – М.:Издательско-торговый дом «Русская Редакция», 2004. — 576 с.
5. ГавриловаТ.А., Хорошевский В.Ф. Базы знаний интеллектуальных систем. – СПб.: Питер,2001. – 384 с.: ил.
6. ГлушаковС.В., Клевцов А.Л., Программирование в среде Delphi 7.0, Фолио 2003
7. ДьяконовВ.П. Новые информационные технологии, Солон-Пресс, 2005
8. ЗемсковА.И., Шрайберг Я.Л. Электронные библиотеки, Либерея, 2003
9. КлименкоР.Н. Оптимизация и автоматизация работы на ПК на 100% (+CD), Питер Пресс,2007
10. Колин К.К. Фундаментальныеосновы информатики: социальная информатика / Учебное пособие для вузов. –М.: Академический проект, 200 –350 с.
11. Кондратьев Г.Г. ОсваиваемWindows XP, Питер, 2005
12. Коплиен Дж.,Мультипарадигменное проектирование для C++, Питер, 2005
13. Красильникова В.А. Становлениеи развитие компьютерных технологий обучения: Монография. – М.: ИИО РАО, 2002. –168 с.
14. Круглински Д., Уингоу С,Шеферд Дж. Программирование на Microsoft Visual C++ 6.0 для профессионалов./Пер, с англ. – СПб: Питер; М.: Издательско-торговый дом «Русская Редакция»,2004. – 861 с.
15. Леонтьев Б.К.,Мультимедия Microsoft Windows без страха, Новый издательский дом, 2005
16. Мандел Т. Дизайнинтерфейсов, ДМК, 2005
17. Музыченко Е.В., ФроловИ.Б., Мультимедия для Windows, 2003
18. Пайс А. Гении науки. – М.:Институт компьютерных исследований, 2002
19. Архангельский А.А. Программированиев Delphi. – М.: Бином, 2003. – 1231 с.
20. Гофман В.Э., ХомоненкоА.Д. Delphi 5. – СПб.: БХВ – Санкт Петербург, 2000. – 800 с.
21. Епанешников А.,Епанешников В. Программирование в среде Delphi: Учебное пособие: В 4-х ч. Ч. 4.Работа с базами данных. Организация справочной системы – М.: ДИАЛОГ – МИФИ,1998. – 400 с.
22. Зубков СергейВладимирович Assembler для Dos, Windows, Unix. – М.: ДМКПресс, 2000. – 652 с.
23. Кэнту Марко Delphi 5.0для профессионалов. – СПб.: Питер, 2001. – 1064 с.
24. Пирогов В.Ю. Assemblerучебный курс. – М.: «Нолидж», 2001. – 926 с.
25. Рейнхардт Р., Ленц Д.У. Flash5. Библия пользователя. – М.: «Вильямс», 2001. – 1164 с.
26. Фигурнов В.Э. IBM PC дляпользователя. Изд. 7-е, перераб. и доп. – М.: ИНФРА – М, 1998. – 640 с.
27. Батищев П.С. ЭлектронныйOn-Line учебник по курсу информатика.
28. Ивановский Р.И. Компьютерныетехнологии в науке и образовании. Практика применения систем Math CAD Pro,Высшая школа, 2003
29. Каймин В.А., Жданов В.С.и др. «Информатика» для поступающих в ВУЗы. Москва, АСТ, 2006 г.
30. Кудрявцев Е.М. Оформлениедипломного проекта на компьютере, АСВ, 2004