Автор работы: Пользователь скрыл имя, 15 Мая 2013 в 05:41, магистерская работа
У результаті виконання магістерської роботи отримано наступні наукові та практичні результати:
вдосконалено методи для нагромадження і аналізу кількісних даних про використання комп’ютерних ресурсів, що на відміну від існуючих враховують тривалість інтерактивної взаємодії з користувачем.
розроблено Web-орієнтоване програмне забезпечення для аналізу і візуалізації даних про користування комп’ютерними ресурсами вищих навчальних закладів.
HANDLE hSnapshot=CreateToolhelp32Snap
TH32CS_SNAPPROCESS, // Формувати список процесів
0); // При формуванні списку
PROCESSENTRY32 pinfo; // Об’єкт для збереження інформації
// про кожен процес, що в даний момент виконується в ОС
Process32First(
hSnapshot, // Ідентифікатор „знімку процесів”
&pinfo); // Структура, що описує поточний процес
do{ // Якщо поточний процес має шуканий ідентифікатор,
if (pid == pinfo.th32ProcessID){ // то запам’ятати його
out << pinfo.szExeFile <<"\n"; // назву у файлі out
break; // вийти з циклу пошуку
}
} while(Process32Next(hSnapshot, &pinfo)); // Перейти до наступного процесу, якщо ще не переглянуто всі.
Цей фрагмент записує у вихідний потік out назву виконуваного файлу, графічне вікно якого на даний момент є активним.
Розглянемо реалізацію алгоритму 2.2, що наведена в додатку Б. Перш за все підключаються бібліотечні файли, що використовуються для отримання даних з ядра ОС та їх збереження у файл. Бібліотечний файл "stdafx.h" підключається автоматично середовищем Visual C++ 6.0, що використовувався для розробки програми. Відомо, що 6.0 не є найсучаснішою версією середовища, оскільки на сьогодні доступна новіша його версія – Visual Studio 2010. Згодом ми розглянемо особливості розробки системної частини саме в Visual С++ 2010.
Заголовочний файл <windows.h> містить декларації системних викликів ядра ОС Windows. Ці системні виклики, як і заголовочний файл спільні для всіх версій ОС Windows, що використовуються на даний момент, включно з Windows 7. Бібліотечний файл <fstream> необхідний для доступу до функцій буферезованого отримання і збереження даних у файлову систему. Бібліотечний файл <iostream> призначений для консольного вводу і виводу, що в даній програмі використовуватиметься здебільшого для початкового відлагодження і не потрібний при нормальному її функціонуванні. Заголовочний файл <strstream> необхідний для створення об’єктів класу istrstream, що дозволяє обробляти стрічку по фрагментах, що, відокремленні пробілами. Фрагменти при цьому можуть бути різного типу, наприклад: стрічки, числа і т.п.
Заголовочний файл <tlhelp32.h> потрібен для отримання оголошення системних викликів CreateToolhelp32Snapshot, Process32First та Process32Next, що призначені для отримання списку процесів, що в даний момент виконуються під керуванням ОС. Цей список необхідний для виконання відображення (1.5).
Далі ідуть оголошення констант у стилі С через директиву препроцесора #define. Перша константа BUF_SIZE описує розмір буфера, що використовується для отримання стрічок із тестового файла, де протоколюються події зміни активного вікна системи Windows (foreground window). Константа SBUF описує об’єм невеликого буфера для збереження коротких тимчасових стрічок символів у різних частинах програми. Значення цих констант пропонуємо обрати із задоволенням умови BUF_SIZE >= SBUF. При цьому SBUF може бути навіть в десять разів менший за BUF_SIZE.
Константа DATESTR_SIZE описує довжину стрічки, що придатна для збереження інформації про дату. Цей розмір встановлено у відповідності до національного стандарту цифрового представлення дати, згідно з яким на день місяця і номер місяця виділено по два знаки, а на рік виділено чотири знаки: дд.мм.рррр. Усі частини дати розділені між собою крапками, наприклад 02.04.2011. Таким чином для збереження дати у цьому форматі достатньо десяти символів. Ще один символ необхідно додати для збереження завершального нуля ‘\0’, що є необхідним атрибутом будь-якої стрічки, що представляється масивом символів char str[] у мовах С та С++. Таким чином константа DATESTR_SIZE дорівнює 11 символам.
Константа NATURAL_SIGNS_NUMBER описує кількість символів натурального числа, що достатні для представлення числа одиниць часу, протягом яких користувач користувався вікном тієї чи іншої програми протягом однієї доби. Цей час прив’язується до доби, бо розроблювана утиліта записує поряд з даними про назву використовуваного процесу дату, у яку фіксувалося спостереження про активність вікна даного процесу. Оскільки для обліку кількості часових інтервалів використовуватиметься тип даних unsigned long, що на 32-розрядних комп’ютерах може набувати значення від 0 до 232-1, що є числом порядку 1010, то натуральне число кількості часових інтервалів можна описати стрічкою з 10 знаків. Таким чином кількість часових інтервалів, протягом яких те чи інше вікно було активним буде описуватися натуральним числом від 1 до 9999999999. Такої кількості часових інтервалів достатньо для опису будь-якої практично-доцільної роздільної здатності спостережень за тривалістю активності вікна протягом доби (щохвилини, щосекунди, щомілісекунди), оскільки в добі є лише 1000*60*60*24=86400000 мілісекунд, для чого достатньо восьми знаків. З цього випливає, що константу числа символів натурального числа кількості інтервалів часу активності вікна NATURAL_SIGNS_NUMBER=10 вибрано з достатньо великим запасом. Константа LOGFILENAME описує назву файла, куди будуть зберігатися усі дані про активність вікон операційної системи.
Згідно з новим стандартом С++ щодо іменування, заголовочні файли з класами стандартної бібліотеки С++ “STL” було підключено без розширення h. Також, згідно того ж стандарту було додано оператор явного розіменування простору імен стандартної бібліотеки using namespace std.
Декларацію основної функції Windows-програми WinMain було згенеровано автоматично середовищем Visual Studio 6.0 вибором типу проекту “Win32 Application”. Жоден з аргументів цієї функції HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow не використовується в роботі програми.
Функція
WinMain починається з декларації буфера
natural_number_format, що міститиме стрічку
форматування натурального числа кількості
часових інтервалів активності вікна.
Ця стрічка форматування генерується
відповідно до стандартів бібліотеки
вводу-виводу stdio, зокрема функцій printf
та scanf, тобто складається з символу проценту
та формату типу, що виводиться. Оскільки
для формування самої стрічки формату
натурального числа викоритовується функція
sprintf, то символи проценту, що не використовуються
як керуючі послідовності, необхідно подвоювати.
У програмі записано наступний виклик
функції: sprintf(natural_number_format,
“%010lu”,
де передостанній символ l це, звісно, не одиниця, а мала латинська літера L, що означує тип long, останній символ u відповідає означенню unsigned. Загалом вищенаведену керуючу послідовність можна прочитати таким чином: надрукувати беззнакове довге ціле число (unsigned long integer), зарезервувавши під нього 10 знаків з передуючими нулями.
Далі в програмі іде оголошення змінних лічильника COUNTER типу беззнакового довгого цілого числа (unsigned long integer) та файлового покажчика TODAY_POS. Файлові покажчики використовуються для збереження і зміни поточної позиції зчитування або запису файла при використанні потокового файлового вводу-виводу (класів бібліотеки fstream).
Згодом виділяється пам’ять на буфер поточної дати CURDATE довжиною DATESTR_SIZE та буфер стрічки даних buf, що використовуватиметься у потоковому вводі з файла. У буфер buf будуть отримуватися стрічки файла-протоколу LOGFILENAME по одній, стрічка за стрічкою.
Далі оголошується вихідний потік out, що є об’єктом класу ofstream і буде згодом використовуватися для модифікації файла-протоколу LOGFILENAME. Оскільки на початку свого функціонування програма повинна обійти всі попередні записи файлу-протоколу, то вона спочатку відкриває цей файл тільки на зчитування. Таку стратегію застосовано з тією метою, щоб уникнути випадкових втрат даних у випадках, коли комп’ютер аварійно вимикається. Файли, що були відкриті в режимі тільки на зчитування не пошкоджуються, оскільки операційна система не виділяє ніяких додаткових буферів на запис, знайдення яких після аварійного перезавантаження комп’ютера могло б свідчити про наявність потенційно не збережених, а, отже, втрачених даних. Крім того, деякі файлові системи здійнюють додаткові дії із перегрупування таблиць розміщення кластерів або індексних таблиць, при відкритті файлів на запис. Це здійснюється з метою забезпечення можливостей збільшувати об’єм файла.
Операція
відкриття файла вимагає
out.open(LOGFILENAME,ios::app)
Далі у програмі декларується булева змінна for_first_time, яка описує чи програму щойно запущено. Якщо вона дорівнює істині, то програма щойно запущена і ще зовсім не аналізувала файла-протоколу. Перевірка цієї змінної використовується згодом у основному циклі програми з метою пришвидшення пошуку місця зміни існуючих та додавання нових записів у протокол. Оскільки облік активних вікон виконується з прив’язкою до поточної дати, то значення хибності цієї булевої змінної означатиме, що файл-протокол вже раз переглядався і змінна позиції у файлі TODAY_POS вказує на місце, де розпочинаються записи, що асоціюються з поточною датою.
Вказівник TODAY_POS на місце у файлі, де розпочинаються записи про активність вікон у поточну добу, працюватиме вірно навіть при переході на наступну добу. При цьому швидкість пошуку пришвидшиться, оскільки записи у файл поміщаються в хронологічному порядку. Докладніше про це йтиме мова далі у описі циклу пошуку місця записів поточної доби.
Усю системну утиліту збору даних про активність вікон та обробку даних у ній спроектовано за принципами безстанового протоколу (stateless protocol). Це означає, що як при запланованому так і аварійному зупині програми не втрачається ніяких даних. При повторному запуску зупинена програма працює так, ніби виконує чергову ітерацію свого головного циклу, без уваги на те, як, коли і за яких обставин її закрили. Тобто цю програму можна безперешкодно зупиняти у будь-який момент її роботи без ризику втратити будь-які дані.
При проектуванні програми особливу увагу зосереджувалося на тому, що вона повинна надійно працювати без перезапусків протягом діб. Береться до уваги також можливість введення комп’ютера, на якому вона працює, в режим гібернації. При цьому програма повинна працювати безпомилково незалежно від кількості і тривалості операцій введення і виведення комп’ютера з режиму гібернації.
Далі у програмі знаходиться основний робочий цикл. Його організовано у вигляді так званого „вічного циклу” while(true), що завершиться лише при подачі користувачем спеціального сигналу ззовні або аварійно при знеструмленні або пошкодженні апаратного забезпечення комп’ютера. При цьому будь-який варіант зупину програми обробляється однаково у спосіб, що запобігає втраті нагромаджених даних та підтримує формат файла у валідному стані.
Перший крок основного циклу за допомогою об’єкта потокового файлового введення ifstream відкриває файл-протокол у режимі тільки для читання:
ifstream in(LOGFILENAME);
Одразу після відкриття файла, перевіряється стан потоку, чи не відбулося при виконанні операції відкриття файла якоїсь помилки введення-виведення. Це здійснюється за допомогою виклику методу отримання інформації про стан файлового вводу: int fstate = in.rdstate(). Якщо результуюче значення змінної fstate має включеними біти ios::badbit чи ios::failbit, то виводиться повідомлення про помилку відкриття файлу у вигляді діалогового вікна MessageBox і програма завершується з кодом 1. Насправді така ситуація може виникнути лише в тих умовах, коли файл LOGFILENAME вже відкрито якимсь іншим процесом у ексклюзивному режимі, тобто без дозволу на спільне читання (shared read, sh_read). Загалом слід зазначити особливість програмування на мові С++ без застосування операторів обробки виключних ситуацій, які появилися у цій мові порівняно недавно. Ця особливість полягає у необхідності перевірки успішності кожної операції вводу-виводу при її ініціації. Якщо цього не зробити, то програма просто продовжить функціонувати без жодної користі для користувача або зависне, не подаючи ніяких помилок часу виконання. Докладніше спосіб відлагодження однієї з таких ситуацій подано при описі циклу пошуку поточної дати.
Далі, якщо основний цикл програми проходиться не вперше (булеву змінну for_first_time встановлено в хибність), то змінна позиції у файлі TODAY_POS вказує на місце у файлі, де розпочинаються сьогоднішні записи спостережень активності вікон (ті, що асоційовані з поточною датою). Тому в цьому випадку позиція зчитування у вхідному потоці пересувається в місце, на яке вказує змінна TODAY_POS, для чого викликається метод seekg(TODAY_POS) над об’єктом файлового вводу in.
Наступною операцією основного циклу є визначення сьогоднішньої дати. Це здійснюється шляхом оголошення вузла stCURDATE, що є об’єктом структури SYSTEMTIME та передачею адреси цього вузла у системний виклик отримання системного часу. Одним з таких викликів є GetSystemTime, що записує у вказаний вузол дату і час у форматі універсального глобального часу (за Гринвічем) – Coordinated Universal Time (UTC). У зимовий період цей час відрізняється від київського на плюс дві години, тобто до часу UTC слід добавити дві години, у літній час до нього слід добавити три години. Насправді у розроблюваній програмі використовується лише день місяця, номер місяця та рік, а дані про час ігноруються. Однак з цього випливає, що, наприклад, коли взимку за київським часом вже розпочався відлік нової доби, то за універсальним глобальним часом буде 22:00 вчорашньої дати. Уникнути такої плутанини можна замінивши системний виклик GetSystemTime на GetLocalTime, що записує у вузол тієї самої структури дату і час відповідно до локального часового поясу, що налаштований в операційній системі. Значення дати і часу, що повертається цим викликом автоматично враховує перехід на літній чи зимовий час. Проте, слід зауважити, що надання переваги виклику GetLocalTime перед викликом GetSystemTime не таке вже і принципове, бо програма розробляється перш за все для учбових закладів, де заняття дуже рідко завершуються пізніше за 22:00.
Після заповнення вузла stCURDATE даними про поточну локальну дату і час здійснюється перетворення інформації про дату у стрічку символів згідно національного стандарту, де на число і номер місяця відведено по два знаки з передуючими нулями, а на рік – чотири знаки. Усі частини дати розділені крапками. Перетворення необхідне, оскільки дані у вузлі stCURDATE зберігаються у вигляді послідовності комп’ютерних слів (набору байтів, що представляють число у двійковому форматі), які непридатні для читання людиною і передачі по мережевих протоколах, що базуються на стандартній системі кодування символів ASCII. Для виконання операції перетворення використано функцію sprintf, що є частиною стандартної бібліотеки мови С. Формат виводу задано у вигляді послідовності символів, що представляють десяткові числа. Утворена стрічка символів придатна для прочитання людиною, на відміну від комп’ютерних слів у двійковому форматі.