Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Диплом1.1.docx
Скачиваний:
14
Добавлен:
08.02.2016
Размер:
147.57 Кб
Скачать

4 Розробка та програмування інформаційної системи

4.1 Розробка ТСР серверу

Transmission Control Protocol (TCP) (протокол управління передачею) - один з основних мережевих протоколів Інтернету, призначений для управління передачею даних в мережах і підмережах TCP / IP. Виконує функції протоколу транспортного рівня моделі OSI. TCP - це транспортний механізм, що надає потік даних, з попередньою установкою з'єднання, за рахунок цього дає впевненість у достовірності одержуваних даних, здійснює повторний запит даних у разі втрати даних і усуває дублювання при отриманні двох копій одного пакета (див. також T / TCP) . На відміну від UDP гарантує цілісність переданих даних і повідомлення відправника про результати передачі. Реалізація TCP, як правило, вбудована в ядро ​​ОС, хоча є й реалізації TCP контексті програми.Коли здійснюється передача від комп'ютера до комп'ютера через Інтернет, TCP працює на верхньому рівні між двома кінцевими системами, наприклад, браузером і веб-сервером. Також TCP здійснює надійну передачу потоку байтів від однієї програми на деякому комп'ютері до іншої програмі на іншому комп'ютері. Програми для електронної пошти і обміну файлами використовують TCP. TCP контролює довжину повідомлення, швидкість обміну повідомленнями, мережевий трафік. При обміні даними приймач використовує номер послідовності, який міститься в одержуваних сегментах, для відновлення їх початкового порядку. Приймач повідомляє передавальну сторону про номер послідовності байт, до якої він успішно отримав дані, включаючи його в поле «номер підтвердження». Всі одержані дані, пов'язані з проміжку підтверджених послідовностей, ігноруються.Якщо отриманий сегмент містить номер послідовності більший, ніж очікуваний, то дані з сегмента буферизирует, але номер підтвердженої послідовності не змінюється. Якщо згодом буде прийнятий сегмент, що відноситься до очікуваного номером послідовності, то порядок даних буде автоматично відновлено виходячи з номерів послідовностей в сегментах. Для того, щоб передавальна сторона не відправляла дані інтенсивніше, ніж їх може обробити приймач, TCP містить засоби управління потоком. Для цього використовується поле «вікно». У сегментах, що направляються від приймача передавальній стороні в поле «вікно» вказується поточний розмір приймального буфера. Передавальна сторона зберігає розмір вікна і відправляє даних не більше, ніж вказав приймач. Якщо приймач вказав нульовий розмір вікна, то передача даних в напрямку цього вузла не відбувається, до тих пір поки приймач не повідомить про більшому розмірі вікна. В деяких випадках передавальний додаток може явно зажадати проштовхнути дані до деякої послідовності приймає додатком, не буферизируя їх. Для цього використовується прапор PSH. Якщо в отриманому сегменті виявляється прапор PSH, то реалізація TCP віддає все буферізірованний на поточний момент дані приймає додатком. «Проштовхування» використовується, наприклад, в інтерактивних програмах. У мережевих терміналах немає сенсу чекати введення користувача після того, як він закінчив набирати команду. Тому останній сегмент, що містить команду, зобов'язаний утримувати прапор PSH, щоб додаток на приймаючій стороні змогло розпочати її виконання.

Створення ТСР серверу функція старт

void Server::start()

{

if (!listen(QHostAddress::LocalHost, 8080))

emit addLogMessage("can`t start server at localhost:8080");

else

emit addLogMessage("Server successfuly started at localhost:8080");

}

void Server::incomingConnection(int handle)

{

if (!firstClient){

firstClient = new Socket(this);

firstClient->setSocketDescriptor(handle);

firstClient->setType(Server::FirstClient);

}else if (!secondClient){

secondClient = new Socket(this);

secondClient->setSocketDescriptor(handle);

secondClient->setType(Server::SecondClient);

firstClient->setChatClient(secondClient);

secondClient->setChatClient(firstClient);

}else

emit addLogMessage("Another one user try to connect to ChatCrypto");

}

ТСР протокол

#ifndef DEFINES_H

#define DEFINES_H

#define client_hello 1

#define server_hello 2

#define client_send_msg 3

#endif // DEFINES_H

Протокол управління передачею даних в DoD стандарті (TCP). Даний стандартгрунтується  на дев'яти  попередніх  виданнях ARPA специфікації TCP, даний  текстсильно  відрізняється від них. В нього внесені великі зміни як щодо концепцій, так і щодо тексту. Дане видання  прояснює  деякі  деталі  протоколу і не включаєвирівнювання за розміром  буфера в кінці листа, а також  перевизначає  механізмлистів  як push  функцію.

Протокол  управління  передачею (TCP) призначений для  використання  в  якості надійного протоколу  спілкування  між хост-комп'ютерами у комунікаційнихкомп'ютерних мережах з  комутацією  пакетів,  а  також в системах, які об'єднуютьтакі мережі. Даний документ описує функції, які повинні виконуватися протоколом управлінняпередачею, програму, яка реалізує протокол, а також її інтерфейс з програмамиабо користувачами, які потребують її послуги.

Комп'ютерні комунікаційні системи відіграють все більш важливу роль у військових, урядових і цивільних додатках. Цей документ в першу чергу висвітлює вимоги до комп'ютерних комунікацій у військовій галузі, і особливо до стійкості в умовах недостатньої надійності комунікацій і можливості перевантажень. Тим не менш, багато з цих проблем мають місце також в цивільному та урядовому секторі. В умовах, коли стратегічні і тактичні мережі комп'ютерних комунікацій виникають і зникають, важливо забезпечити кошти для їх зі єднання, а також стандартні протоколи комунікації між процесами, які б підтримували великий діапазон прикладних програм. Передбачаючи потребу в таких стандартах, Представництво Секретаріату Оборони з науково-дослідним і дослідно-конструкторських робіт пред'явило протокол управління передачею (Transmission Control Protocol - TCP), описаний тут, на основі стандартизації DoD протоколу комунікацій між процесами. TCP - це протокол забезпечення надійності прямих з'єднань, створений для багаторівневої ієрархії протоколів, що підтримують міжмережеві програми.Протокол TCP забезпечує надійність комунікацій між парами процесів на хост-комп'ютерах, включених в різні комп'ютерні комунікаційні мережі, які об'єднані в єдину систему. Щодо надійності протоколів більш низького, ніж TCP, рівня зроблені досить скромні запити. TCP передбачає, що він може отримати простий, потенційно ненадійний сервіс для своїх датаграм з боку протоколів нижнього рівня. В принципі, протокол TCP повинен бути працездатний на великому наборі комунікаційних систем, починаючи з кабельних з'єднань та закінчуючи мережами з переключенням пакетів чи електричних ланцюгів. Протокол TCP грунтується на концепціях, вперше описаних авторами Cerf і Kahn в документі . TCP займає в багаторівневій архітектурі протоколів нішу безпосередньо над протоколом Internet, який дозволяє протоколу TCP відправляти та отримувати сегменти інформації змінної довжини, укладені в оболонку Internet датаграм. Internet датаграма надає засоби для адресації відправника і одержувача сегментів TCP в різних мережах. Протокол Internet також здійснює будь-яку фрагментацію та зборку сегментів TCP, необхідну для здійснення передачі та доставки через безліч мереж та проміжних шлюзів. Протокол Internet також обробляє інформацію про пріоритет, класифікації безпеки, а також здійснює розмежування TCP сегментів. Так що дана інформація може бути передана безпосередньо через безліч мереж

Велика частина цього документа написана у зв'язку  з  реалізаціями  TCP  протоколу, які разом з  протоколами  більш  високого  рівня  присутні  на хост-комп'ютері. Деякікомп'ютерні системи будуть  включатися  в мережі  через головні комп'ютери, що містять  протоколи рівнів  TCP і Internet, а  також специфічне мережеве програмнезабезпечення. Специфікація  TCP  описує її інтерфейс з протоколами  більш високого  рівня, якіопинилися  здійсненні навіть у разі головного  комп'ютера, якщо  реалізований відповідний протокол  спілкування  між хост-комп'ютером і головним  комп'ютером. Протокол TCP взаємодіє з одного боку з користувачем чи прикладною програмою, а з іншого - з протоколом більш низького рівня, таким як протокол Internet. Інтерфейс між прикладним процесом та протоколом TCP ми пояснюємо з прийнятною деталізацією. Цей інтерфейс складається з набору викликів, які схожі на виклики операційної системи, що надаються прикладному процесу для управління файлами. Наприклад, в цьому випадку є виклики для відкриття і закриття з'єднань, для відправки та отримання інформації на встановлених з'єднаннях. Передбачається також, що протокол TCP зможе асинхронно взаємодіяти з прикладними програмами. Хоча розробникам TCP протоколу та надана значна свобода у створенні інтерфейсів, які відповідають властивостям конкретної операційної системи, все ж від будь-якій прийнятній реалізації потрібні якісь обов'язкові мінімальні функції інтерфейсу між протоколом TCP і користувачем. Інтерфейс між протоколом TCP та протоколами більш низького рівня за дан в значно меншій мірі, за винятком того, що повинен існувати якийсь механізм, за допомогою якого ці два рівня можуть асинхронно обмінюватися інформацією один з одним. Зазвичай вважають, що протокол нижнього рівня задає цей інтерфейс.Протокол TCP спроектований так, щоб працювати з досить різноманітною середовищем об'єднаних комп'ютерних мереж. В даному документі передбачається, що протокол нижчого рівня - це Internet .

Як зазначалося раніше, головною метою протоколу TCP є забезпечення надійного, безпечного сервісу для логічних ланцюгів чи з'єднань між парами процесів. Щоб забезпечити такий сервіс, базуючись на менш надійних комунікаціях Internet, система повинна мати можливості для роботи в наступних областях: базова передача даних достовірність управління потоком поділ каналів робота із з'єднаннями пріоритет і безпека Основні дії протоколу TCP у кожній з цих областей описані у наступних параграфах. Базова передача даних Протокол TCP здатний передавати неперервні потоки октетів між своїми клієнтами в обох напрямках, пакуючи деяку кількість октетів у сегменти для передачі через системи Internet. У загальному випадку протоколи TCP вирішують за своїм розсудом, коли проводити блокування та передачу даних. Іноді користувачам буває необхідно переконатися в тому, що всі дані, передані ними протоколу TCP, вже відправлені. Для цієї мети визначена функція проштовхування (push). Щоб переконатися в тому, що дані, відправлені протоколу TCP, дійсно передані, відправник вказує, що їх слід проштовхнути до одержувача. Проштовхування призводить до того, що програми протоколу TCP одразу здійснюють відправлення і, відповідно, отримання залишаються даних. Правильно здійснене проштовхування може бути невидиме для отримувача, а сама функція проштовхування може не мати маркера межі запису. Достовірність Протокол TCP повинен мати захист від руйнування даних, втрати, дублювання та порушення черговості отримання, викликаних комунікаційною системою Internet. Це досягається присвоєнням чергового номера кожному переданому октету, а також вимогою підтвердження (ACK) від програми TCP, яка приймає дані. Якщо підтвердження не отримано протягом контрольного інтервалу часу, то дані посилаються повторно. З боку отримувача номери черги використовуються для відновлення черговості сегментів, які можуть бути отримані у неправильному порядку, а також для обмеження можливості появи дублікатів. Пошкодження фіксуються за допомогою додавання до кожного переданому сегменту контрольної суми, перевірки її при отриманні і подальшої ліквідації дефектних сегментів. До тих пір, поки програми протоколу TCP продовжують функціонувати коректно, а система Internet не розвалилася повністю на складові частини, помилки пересилання не впливатимуть на правильне одержання даних. Протокол TCP захищає від помилок комунікаційної системи Internet. Управління потоком Протокол TCP дає кошти одержувачу керувати кількістю даних, що посилаються йому відправником. Це досягається поверненням так званого "вікна" (window) разом з кожним підтвердженням, яке вказує діапазон прийнятних номерів, наступних за номером останнього успішно прийнятого сегменту. Вікно визначає кількість октетів, яке відправник може послати до отримання подальших вказівок. Поділ каналів Щоб дозволити на окремо взятому комп'ютері багатьом процесам одночасно використовувати комунікаційні можливості рівня TCP, протокол TCP надає на кожному хост-комп'ютері набір адрес чи портів. Разом з адресами мереж та хост-комп'ютерів на комунікаційному рівні Internet вони утворюють сокет (socket - роз'єм). Кожне з'єднання унікальним чином ідентифікується парою сокетів. Таким чином, будь-який сокет може одночасно використовуватися в багатьох з'єднаннях. Співвіднесення портів та процесів здійснюється кожним хост-комп'ютером самостійно. Проте виявляється корисним зв'язувати часто використовувані процеси (такі як "logger" чи сервіс з розподіленням часу) з фіксованими документованими сокетами. Цей сервіс можна згодом використовувати через відомі адреси. Установка і настройка адрес портів для інших процесів може включати більш динамічні механізми.Робота з сполуками. Механізми управління потоком та забезпечення достовірності, описані вище, вимагають, щоб програми протоколу TCP ініціалізували та підтримували певну інформацію про стан кожного потоку даних. Набір такої інформації, що включає сокети, номери черги, розміри вікон, називається з'єднанням. Кожне з'єднання унікальним чином ідентифікується парою сокетів на двох кінцях. Якщо два процеси бажають обмінюватись інформацією, відповідні програми протоколу TCP повинні спочатку встановити з'єднання (на кожному боці ініціалізувати інформацію про статус). По завершенні обміну інформацією з'єднання повинно бути розірвано або закрито, щоб звільнити ресурси для надання іншим користувачам. Оскільки з'єднання повинні встановлюватися між ненадійними хост-комп'ютерами та через ненадійну комунікаційну систему Internet, то щоб уникнути помилкової ініціалізації з'єднань використовується механізм підтвердження зв'язку з хронометрувати номерами черги. Пріоритет і безпека Користувачі протоколу TCP можуть вимагати для свого з'єднання пріоритет і безпеку. Передбачені прийняті за замовчанням характеристики з'єднань, коли такі параметри не потрібні.

Набір даних, переданих по з'єднанню, можна розглядати як потік октетів.Користувач, що відправляє дані, вказує при запиті по посилку, чи дані, що відправляються при цьому запиті, негайно проштовхувати через мережу до одержувача. Вказівка ​​здійснюється установкою прапора PUSH (проштовхування). Програма протоколу TCP може збирати дані, що приймаються від користувача, а потім передавати їх в мережу на свій розсуд у вигляді сегментів. Якщо ж виставлений запит на проштовхування, то протокол має передати все не відправлені раніше дані. Коли програма протоколу TCP, яка приймає дані, стикається з прапором проштовхування, їй не слід очікувати отримання нових даних по мережі до тих пір, поки вже наявні дані не будуть передані що чекає їх місцевим процесу. Немає потреби прив'язувати функції проштовхування до кордонів сегмента. Дані, що містяться в будь-якому сегменті, можуть бути результатом одного або кількох запитів на посилку. Або ж один запит може породити декілька сегментів. Метою функції проштовхування і прапора PUSH є проштовхування даних через мережу від відправника до одержувача. Функція не здійснює обробки самих даних. Існує зв'язок між функцією проштовхування та використанням буферів даних в інтерфейсі між користувачем і протоколом TCP. Кожен раз, коли в буфер одержувача приходять дані з прапором PUSH, вміст цього буфера передається користувачеві на обробку, навіть якщо буфер і не був заповнений. Якщо приходять дані заповнюють буфер користувача до того, як отримана команда проштовхування, користувачеві відправляється блок даних, відповідний розміру буфера. Протокол TCP має також засоби для повідомлення одержувачу, що з деякого моменту він має справу з терміновими даними. Протокол TCP не намагається визначити, що саме користувач робить зі чекають обробки терміновими даними. Проте зазвичай передбачається, що одержує дані процес буде робити зусилля для швидкої обробки строкових даних. Пріоритет і безпека протокол TCP використовує тип сервісу і опцію безпеки протоколу Internet з тим, щоб користувачам протоколу TCP забезпечити пріоритет і безпеку на кожному з'єднанні. Не всі модулі протоколу TCP обов'язково будуть діяти в багаторівневою системою забезпечення безпеки. Деякі модулі обмежуються тільки звичайними, неспецифічними сполуками, інші обмежуються лише першим рівнем безпеки та закритості. Отже, деякі реалізації протоколу TCP і послуг для користувачів можуть використовувати лише частина багаторівневої системи безпеки. Модулі TCP, що діють в багаторівневою системою безпеки, повинні адекватно виставляти в відсилаються сегментах прапори безпеки і пріоритету. Такі модулі TCP повинні також дозволяти своїм клієнтам або вищестоящим протоколам, таким як Telnet і THP, вказувати необхідний рівень безпеки, закритості і пріоритету для встановлюваних сполук.

4.2 TCP протокол та обмін данними

У змінній server_status - зберігається статус QTcpServer, щоб не  відбувалося  ексцесівпри роботі сервера (якщо 0 - то сервер не  слухає  порт, 1 - слухає). Сигнали в даному випадку вирішують зайвий раз проблему з прослуховуван ямпорту, тобто слот newuser () в даний момент викликається тільки тоді,  колиз'являється  нове підключення до сервера.

tcpServer = new QTcpServer(this);

connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newuser()));

if (!tcpServer->listen(QHostAddress::Any, 33333) && server_status==0)

{

qDebug() << QObject::tr("Unable to start the server: %1.").arg(tcpServer->errorString()); } else { server_status=1; qDebug() << QString::fromUtf8("Сервер запущен!");

}

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

    if (server_status == 1) {         qDebug () << QString :: fromUtf8 ("У нас нове з'єднання!");         QTcpSocket * clientSocket = tcpServer-> nextPendingConnection ();         int idusersocs = clientSocket-> socketDescriptor ();         SClients [idusersocs] = clientSocket;         connect (SClients [idusersocs], SIGNAL (readyRead ()), this, SLOT (slotReadClient ()));     } QMap <int,QTcpSocket *> SClients;

Дана карта зберігає об'єкти створених сокетів. Її використовую наприклад якщо примусово зупиняю сервер і мені необхідно закрити відкриті сокети. Якщо їх не закрити, то клієнт буде ще довго чекати відповідь від нашого сервера і не закривати з'єднання. Нижче викладено варіант примусового закриття всіх сокетів.

    if (server_status == 1) {

        foreach (int i, SClients.keys ()) {

            QTextStream os (SClients [i]);

            os.setAutoDetectUnicode (true);

            os << QDateTime :: currentDateTime (). toString () << "\ n";

            SClients [i] -> close ();

            SClients.remove (i);

        }         tcpServer-> close ();

        qDebug () << QString :: fromUtf8 ("Сервер зупинений!");

        server_status = 0;

    } При створенні нового сокета сигнал readyRead (), він виконується коли клієнт передає якісь дані на наш сервер, в цей момент ми і будемо давати відповідь нашому клієнтові, попередньо отримавши дані.

    QTcpSocket * clientSocket = (QTcpSocket *) sender ();

    int idusersocs = clientSocket-> socketDescriptor ();

    QTextStream os (clientSocket);

    os.setAutoDetectUnicode (true);

    os << "HTTP/1.0 200 Ok \ r \ n"

          "Content-Type: text / html; charset = \" utf-8 \ "\ r \ n"

          "\ R \ n"

          "<h1> Nothing to see here </ h1> \ n"

          << QDateTime :: currentDateTime (). ToString () << "\ n";

    qDebug () << clientSocket-> readAll () + "\ n \ r");

    clientSocket-> close ();

    SClients.remove (idusersocs);

Таким чином ми отримуємо сервер (наприклад HTTP), який слухає порт ххххх, зможе обробляти відразу декілька запитів одночасно і віддавати потрібний результат.

4.3 ТСР клієнт

Client показує,  як створити клієнта для простої сервіс мережі за допомогою  QTcpSocket. Наприклад  призначений  для  одночасного  запуску з прикладом Fortune Server аборізьбові приклад сервера Fortune. У цьому  прикладі  використовується проста  QDataStream на основі  протоколупередачі  даних для запиту рядки тексту зі стану сервера  (на прикладі сервераFortune).  Клієнт запитує стан, просто підключивши до сервера. Потім сервервідповідає 16-бітний (quint16) ціле число, що містить  довжину  стан тексту, а потімQString. QTcpSocket  підтримує два основних підходи до мережного програмування:Асинхронний (без блокування) підхід.  Операції плануються і виконуються, коли управління повернеться до циклу подій Qt. Коли операція закінчиться, QTcpSocketвипромінює сигнал. Наприклад, QTcpSocket :: connectToHost () повертає відразу, аколи'єднання встановлено, QTcpSocket випромінює connected (). Синхронний (блокування) підхід. У не GUI і багатопоточних додатків, ви  можетезателефонувати  WaitFor ... ()  функції (наприклад, QTcpSocket :: waitForConnected ()) припиняти  викликає  потік до завершення операції, а підключення до сигналів. У цьому прикладі ми покажемо, асинхронний  підхід.  Блокування  наприклад  Fortune Client показує синхронний підхід. Наш  клас містить  деякі дані, а також декілька приватних слотів:

class Client : public QDialog

{

Q_OBJECT

public:

Client(QWidget *parent = 0);

private slots:

void requestNewFortune();

void readFortune();

void displayError(QAbstractSocket::SocketError socketError);

void enableGetFortuneButton();

void sessionOpened();

Крім віджетів, які становлять графічний інтерфейс користувача, дані входять QTcpSocket покажчик, копія тексту в даний час стан відображається, і розмір пакету, ми в даний час читання (докладніше про це пізніше). Гніздо ініціалізується в конструкторі клієнта. Ми будемо проходити головний віджет, як батьків, так що нам не доведеться турбуватися про видалення гнізда:

 Client :: Client (QWidget * батько)

 : QDialog (батька), networkSession (0)

 {      TcpSocket = новий QTcpSocket (це);

Тільки сигнали QTcpSocket ми повинні в цьому прикладі QTcpSocket :: readyRead (), що означає, що дані були отримані і QTcpSocket :: помилка (), який ми будемо використовувати, щоб зловити будь-які помилки з'єднання:

connect (TcpSocket, SIGNAL (readyRead ()), це, SLOT (readFortune ())); connect (TcpSocket, SIGNAL (помилки (QAbstractSocket :: SocketError)); }

Натискання кнопки Get Фортуна викличе requestNewFortune () слот:

 void Client :: requestNewFortune ()

 {      getFortuneButton-> setEnabled (помилковий);

     BLOCKSIZE = 0;

     TcpSocket-> перервати ();

     TcpSocket-> connectToHost (hostLineEdit-> текст ()

   . PortLineEdit-> Текст () toInt ());

 }

В цей слот ми инициализируем блоку 0, готуючись читати новий блок даних. Тому що ми дозволяємо користувачеві натисніть кнопку Отримати удачі перед попереднім закриттям зв'язку закінчена, ми почнемо переривання попереднього з'єднання, викликавши QTcpSocket :: Abort (). (На незв'язаних гніздо, ця функція нічого не робить.) Потім ми підключенні до сервера стан, викликавши QTcpSocket :: connectToHost (), передавши ім'я хоста і порт з користувальницького інтерфейсу в якості аргументу. В результаті виклику connectToHost (), одна з двох речей може відбутися: З'єднання встановлено. У цьому випадку сервер буде посилати нам удачу.QTcpSocket видасть readyRead () кожен раз, коли вона отримує блок даних. Помилка. Нам потрібно, щоб повідомити користувачеві, якщо з'єднання не вдалося або була порушена. В цьому випадку, QTcpSocket видасть помилку () і Client :: DisplayError () буде викликаний. Давайте пройдемося по помилку () випадок перший:

Ми видаляємо всі помилки в діалог з допомогою QMessageBox :: Information  ().QTcpSocket :: RemoteHostClosedError ігнорується, так як протокол стану серверазакінчується на сервер закриває з'єднання. Тепер  для  альтернативних  readyRead (). Цей сигнал пов'язаний з

Client ::readFortune ():   void  Client :: readFortune ()

  {       QDataStream в (TcpSocket);

      in.setVersion (QDataStream :: Qt_4_0);      if(bloc.size() == 0) {

          if (TcpSocket-> bytesAvailable () <(INT) SizeOf (quint16))

              return;           in block >>;       }       if (TcpSocket-> bytesAvailable () < quint16)

Протокол заснований на QDataStream, тому ми почнемо з створення  об'єктапотоку, передаючи сокет конструктор QDataStream в. Ми потім явно задатипротокол версії потік QDataStream :: Qt_4_0, щоб ми  використовуємо ту ж версію, стан сервера, незалежно від того, яка версія  Qt клієнт і сервер використовують. Тепер TCP  заснований  на  відправку  потоку даних, тому ми не  можемо  чекати, щоботримати всі свої статки за один раз.  Особливо  на повільну  мережу, то дані можутьбути отримані  в декількох  невеликих  фрагментів.  QTcpSocket буфери всі вступникидані і видає readyRead () для  кожного  bнового  блоку,  який  прибуває,  і це нашаробота, щоб ми отримали всі дані, ми  повинні,  перш  ніж почати аналіз. Відповідьсервера починається з  розміру  пакета,  так що спочатку ми  повинні  переконатися, що ми можемо  прочитати розмір, то ми будемо чекати, поки QTcpSocket отримавповний пакет.       QString nextFortune;

      В >> nextFortune;       if (nextFortune == currentFortune) {

          QTimer :: Singleshot (0, то це, SLOT (requestNewFortune ()));           повернутися;       }       currentFortune = nextFortune;       statusLabel-> зейТех (currentFortune);       getFortuneButton-> setEnabled (правда);   }

Виходимо з допомогою потокових операторів QDataStream на читання долі зрозетки в QString. Після прочитання можна назвати QLabel :: зейТех () длявідображення стану.

3.3 Розробка методу захисту данних

Шифрування блоків за допомогою зміщення байтів є надійним механізмом захисту інформації, стійкість якого можна підвищити привязкою до двох ключів та допоміжними недійсними данними що входять у склад кожного блоку данних. Фрагмент коду показує як розбивається повідомлення

int check_size;

check_size = data.size() % double_key.size();

qDebug() << "check_data = " << check_size;

QStringList iterationKeys = double_key.split("#");

QString DataEncript;

int cript_app = 0;

for (int i = 0; i < iterationKeys.size(); ++i)

{

QString keyBlock = iterationKeys.at(i);

for (int j = 0; j < keyBlock.size(); ++j)

cript_app += keyBlock.at(j).ByteArray;

}

QString tep,complite_data;

for (int ix = 0; ix < data.size(); ++ix)

{

temp = data.at(ix);

complite_data.push_back(tep);

}

Перестановка що на першому єтапі заміщає символи контейнера котрий зберігає у собі повідомлення.

for(int ix = 0; ix < complite_data.size(); ++ix)

{

QString swap,swop;

int center_data;

center_data = complite_data.size()/2;

swap = complite_data.mid(center_data,ix);

swop = complite_data[center_data - ix];

complite_data.insert(ix,swop);

complite_data.insert(complite_data.size() - ix,swap);

}

Генервція випадкового тексту вигляд якого буде схожий до вихідного тексту

тому явно побачити різницю у масиві символів тексту що буде зашифрований не вийде

QString alphaG = "aei ouy ", alphaS = "bcdfghjklm npqrstvwxz ";

QString genTExt;

int startPos, nextPos;

for(int ix = 0; ix < size; ++ix)

{

startPos = rand()%alphaS.size();

nextPos = rand()%alphaG.size();

genTExt.push_back(alphaS.at(startPos));

genTExt.push_back(alphaG.at(nextPos));

}

qDebug() << "gentext" << genTExt;

QString temp1,tem1;

genTExt = genTExt + data;

int sumSize = genTExt.size() + data.size();

for(int ix = 0; ix < sumSize; ++ix)

{

temp1 = genTExt[ix];

tem1 = genTExt[data.size() - 1];

genTExt.push_back(temp1);

genTExt.push_back(tem1);

}

qDebug() << "data" << genTExt;

qDebug() << "gen text" << genTExt;

QByteArray може бути використаний для зберігання як сирих байт (включаючи і '\ 0'), так і традиційних 8-бітних нуль-терминирования рядків. Використання QByteArray зручніше, ніж використання const char *. Тут завжди гарантовано, що дані завершуються '\ 0' і використовується неявне спільне використання даних (copy-on-write) для економії пам'яті та уникнення непотрібного копіювання даних. На додаток до QByteArray Qt також надає клас QString для зберігання строкових даних. У більшості випадків вам більше підійде клас QString. Він зберігає 16-бітові символи в Unicode, що спрощує зберігання не-ASCII і нелатинських символів у вашому додатку. Крім того, QString всюди використовується в Qt API. Два основних випадку, де QByteArray підходить - це, коли вам потрібно зберегти сирі двійкові дані, і коли критично збереження пам'яті (наприклад, в Qt для Embedded Linux). Один із способів ініціалізації QByteArray - просто передати const char * в конструктор. Наприклад, наступний код створює масив з 5 байт, що містить дані "Hello": QByteArray ba ("Hello"); Незважаючи на те, що size () дорівнює 5, байтовий масив також містить в кінці додатковий символ '\ 0', так що, якщо використовується функція, що вимагає покажчик безпосередньо на дані (тобто виклик data ()), то ці дані будуть гарантовано закінчуватися '\ 0'. QByteArray робить повну копію даних const char *, так що ви можете модифікувати їх, не отримавши надалі побічних ефектів. (Якщо, з міркування продуктивності, ви не хочете робити повне копіювання даних, використовуйте QByteArray :: fromRawData ().) Інший спосіб - встановити розмір масиву, використовуючи resize () і ініціалізувати дані побайтно. QByteArray використовує індекси починаються з 0, як прийнято в масивах C + +. Для доступу до байту в конкретній позиції індексу, ви можете використовувати оператор [] (). В неконстантних масивах оператор [] () повертає посилання на байт, яка може бути використана з лівого боку операції присвоювання. Наприклад:

 QByteArray ba;

 ba.resize (5);

 ba [0] = 0x3c;

 ba [1] = 0xb8;

 ba [2] = 0x64;

 ba [3] = 0x18;

 ba [4] = 0xca;

Для доступу "тільки для читання", існує альтернативний синтаксис at ():  for (int i = 0; i <ba.size (); + + i) {

     if (ba.at (i)> = 'a' && ba.at (i) <= 'f')

         cout << "Found character in range [a-f]" << endl;

 }

at () може працювати швидше, ніж оператор [] (), тому що при цьому ніколи не створюється повної копії. Щоб отримати кілька байт за раз використовуйте left (), right () або mid (). QByteArray може вміщати байти '\ 0'. Функція size () завжди повертає розмір всього масиву, включаючи вставлені '\ 0'. Якщо ви хочете отримати довжину даних аж до першого символу '\ 0', але не включаючи його, викличте для масиву qstrlen (). Після виклику resize (), додані байти будуть містити невизначені значення. Щоб проініціалізувати всі байти певним значенням, викличте fill (). Щоб отримати покажчик безпосередньо на символьні дані, викличте data () або constData (). Ці функції повертають покажчик на початок даних. Покажчик гарантовано залишається правильним до тих пір, поки не буде викликана неконстантная функція на QByteArray. Також гарантується, що дані закінчуються байтом '\ 0'. Цей байт '\ 0' автоматично надається класом QByteArray і не враховується в size (). QByteArray надає наступні основні функції для модифікації байт даних: append (), prepend (), insert (), replace () і remove (). Наприклад:  QByteArray x ("and");

 x.prepend ("rock"); / / x == "rock and"

 x.append ("roll"); / / x == "rock and roll"

 x.replace (5, 3, "&"); / / x == "rock & roll"

У функціях replace () і remove () перші два аргументи вказують на позицію, від якої починається видалення, і кількість байт, яке повинно бути вилучено. Коли ви додаєте дані за допомогою append () в непорожній масив, він може бути перерозподілений в пам'яті перед копіюванням в нього нових даних. Ви можете уникнути такої поведінки, викликавши функцію reserve (), яка виділить точну кількість пам'яті. Ви також можете викликати capacity (), щоб дізнатися, скільки пам'яті займає QByteArray в дійсності. Дані, що додаються в порожній масив, не копіюються. Часто треба видалити з масиву незначущі пропуски і символи-роздільники ("whitespace"), такі як '\ n', '\ t', '' і т.п. Якщо ви хочете видалити пробільні символи з обох кінців QByteArray, використовуйте trimmed (). Якщо ви хочете видалити символи-роздільники з обох кінців масиву і замінити послідовності з декількох таких символів одним пропуском всередині байтового масиву, використовуйте simplified (). Якщо ви хочете знайти всі входження символу або підрядка в QByteArray, испоьзуется indexOf () або lastIndexOf (). Перша функція здійснює пошук вперед від зазначеної позиції, а остання - здійснює пошук назад. Обидві функції повертають індекс позиції символу або підрядка, якщо вони були знайдені, в іншому випадку повертається -1. Наприклад, тут наведено типовий цикл, який знаходить всі збіги конкретної підрядка:  QByteArray ba ("We must be <b> bold </ b>, very <b> bold </ b>");

 int j = 0;

 while ((j = ba.indexOf ("<b>", j))! = -1) {

     cout << "Found <b> tag at index position" << j << endl;      + + J;

 } Якщо ви просто хочете лише перевірити, чи містить QByteArray конкретний символ або підрядок, використовуйте contains (). Якщо вам потрібно дізнатися, скільки разів символ або підрядок зустрічаються в масиві, використовуйте count (). Якщо ви хочете поміняти одне значення на інше в усьому масиві, використовуйте одну з двох перевантажених функцій replace () з двома параметрами. Два QByteArray можна порівняти використовуючи перевантажені оператори <(), <= (), == (),> = () і т.д. Порівняння базується виключно на числових значеннях символів масиву і проводиться дуже швидко, але не завжди відповідає бажанням людини.Функція QString :: localeAwareCompare () краще підходить для сортування рядків користувальницького інтерфейсу. Історично склалося, що в QByteArray існує відмінність між неініціалізованих (null byte) масивом і порожнім (empty) масивом. Неініціалізованих масив - це масив, який створений за допомогою конструктора QByteArray () за замовчуванням або конструктором з аргументом (const char *) 0. Порожній масив це масив, що має довжину 0. Неініціалізованих масив завжди порожній, але порожній масив необов'язково буде неініціалізованих:

 QByteArray (). IsNull (); / / поверне true

 QByteArray (). IsEmpty (); / / поверне true

 QByteArray (""). IsNull (); / / поверне false

 QByteArray (""). IsEmpty (); / / поверне true

 QByteArray ("abc"). IsNull (); / / returns false

 QByteArray ("abc"). IsEmpty (); / / поверне false

Всі функції, за винятком isNull (), розглядають неініціалізованих (null) масив, як порожній (empty). Наприклад, data () поверне покажчик на '\ 0' для неініціалізованої (null) масиву (не покажчик null), а QByteArray (), при порівнянні, дорівнює QByteArray (""). Ми рекомендуємо вам завжди використовувати isEmpty () і уникати isNull (). Перевірка данних на достовірність та їх цілісність

QByteArray block;

QDataStream out(&block, QIODevice::WriteOnly);

out.setVersion(QDataStream::Qt_4_0);

out << (quint16)0;

out << Command();

out << Data();

QString msg;

msg += QString::number(Command());

msg += Data();

emit msgRecived(msg);

out.device()->seek(0);

out << (quint16)(block.size() - sizeof(quint16));

write(block);

4 Механізм слотів сигналів

Сигнали і слоти використовуються для зв'язку між об'єктами. Механізм сигналів і слотів - це основна особливість Qt і, ймовірно, основна частина Qt, яка найбільше відрізняється по функціональності від інших бібліотек.

При програмуванні графічного інтерфейсу користувача ми часто хочемо повідомляти одним елементам про зміну інших елементів управління. Більш узагальнено можна сказати, що ми хочемо забезпечити зв'язок між об'єктами будь-яких видів. Наприклад, якщо користувач натискає кнопку Close ми, ймовірно, хочемо, щоб була викликана функція вікна close ().

Більш старі інструментарії забезпечують подібний зв'язок за допомогою функцій зворотного виклику. Зворотний виклик - це покажчик на функцію. Якщо ви хочете, щоб функція обробки повідомила вас про деяке подію, ви передаєте їй покажчик на іншу функцію (відгук). Функція обробки викличе функцію зворотного виклику, коли це буде доречно. Але даний підхід має два фундаментальні недоліки: по-перше, він не тіпобезопасен. Ми ніколи не зможемо перевірити, що функція обробки викликає відгук з правильними аргументами. По-друге, цей метод жорстко пов'язаний з функцією обробки, так як вона повинна знати, який відгук викликати.

У Qt ми ввели техніку, альтернативну функцій зворотного виклику: ми використовуємо сигнали і слоти. Сигнал випускається, коли відбувається певна подія. Віджети Qt мають безліч зумовлених сигналів, і ви завжди можете створити їх підкласи, щоб додати свої сигнали. Слот - це функція, що викликається у відповідь на певний сигнал. Віджети Qt мають безліч зумовлених слотів, але ви, і це стало общеіспользуемой практикою, можете створювати підкласи віджетів і додавати свої слоти для того, щоб обробляти надходять сигнали, як того хочете.

Цей механізм тіпобезопасен: сигнатура сигналу повинна відповідати сигнатурі приймає слота. (Фактично, слот може мати більш коротку сигнатуру, ніж сигнал, який він отримує, оскільки може ігнорувати зайві аргументи.) Сигнали і слоти пов'язані без нежорстко: Клас, що випускає сигнали, не знає і не цікавиться, який із слотів отримає сигнал. Механізм сигналів і слотів Qt гарантує, що, якщо Ви поєднали сигнал зі слотом, слот буде викликатися з параметрами сигналу в потрібний момент. Сигнали і слоти можуть мати будь-яку кількість аргументів будь-яких типів. Вони повністю тіпобезопасни.

Всі класи, успадковані від QObject або одного з його підкласів (наприклад, QWidget) можуть містити сигнали і слоти. Сигнали випускаються при зміні об'єктом свого стану, якщо ця зміна може бути цікаво іншим об'єктам. Всі об'єкти роблять це для зв'язку з іншими об'єктами. Їх не турбує, чи отримує хтось випускаються ними сигнали. Це є істинною інкапсуляцією інформації, і вона гарантує, що об'єкти можуть використовуватися як окремі компоненти програмного забезпечення.

Слоти можуть отримувати сигнал, але вони також є звичайними функціями-членами. Також, як об'єкт не знає, чи отримує хтось сигнали, що випускаються ним, слоти не знають, чи існують сигнали, з ними пов'язані. Це гарантує, що можна створити повністю незалежні Qt компоненти.

Ви можете приєднувати до одного слоту стільки сигналів, скільки вам буде потрібно, і один сигнал може бути з'єднаний зі стількома слотами, скільки вам потрібно. Навіть можливо з'єднувати сигнал безпосередньо з іншим сигналом. (Другий сигнал буде випускатися негайно всякий раз, коли випускається перший.).

Разом сигнали і слоти представляють собою потужний механізм компонентного програмування.

Мінімальна декларація класу C + + може виглядати наступним чином:

class Counter

{

public:

Counter () {m_value = 0;}

int value () const {return m_value;}

void setValue (int value);

private:

int m_value;

};

Невеликий клас, заснований на QObject, може виглядати так:

# Include <QObject>

class Counter: public QObject

{

Q_OBJECT

public:

Counter () {m_value = 0;}

int value () const {return m_value;}

public slots:

void setValue (int value);

signals:

void valueChanged (int newValue);

private:

int m_value;

};

Версія класу, заснована на QObject, має те ж саме внутрішній стан і надає відкриті методи для доступу до нього, але на додаток до цього вона підтримує компонентне програмування з використанням сигналів і слотів. Цей клас, важко зітхнувши сигнал valueChanged (), може повідомляти зовні, що його стан змінився, і має слот, якому інші об'єкти можуть посилати сигнали.

Всі класи, що містять сигнали і слоти, повинні згадати макрос Q_OBJECT на початку своєї декларації. Також вони повинні відбуватися (прямо чи опосередковано) від QObject.

Слоти реалізуються програмістом. Ось можлива реалізація слота Counter :: setValue ():

void Counter :: setValue (int value)

{

if (value! = m_value) {

m_value = value;

emit valueChanged (value);

}

}

Рядок, що містить emit, змушує об'єкт випустити сигнал valueChanged () з новим значенням, переданим в аргументі.

У наступному фрагменті коду ми створюємо два об'єкти Counter і з'єднуємо сигнал першого об'єкта valueChanged () зі слотом другого об'єкта setValue (), використовуючи QObject :: connect ():

Counter a, b;

QObject :: connect (& a, SIGNAL (valueChanged (int)),

& B, SLOT (setValue (int)));

a.setValue (12); / / a.value () == 12, b.value () == 12

b.setValue (48); / / a.value () == 12, b.value () == 48

Виклик a.setValue (12) змушує a випускати сигнал valueChanged (12), який буде отриманий об'єктом b через слот setValue (), тобто буде викликана функція b.setValue (12). Потім b сам випустить сигнал valueChanged (), але так як ніхто не пов'язаний з об'єктом b через сигнал valueChanged (), він буде проігнорований.

Зверніть увагу на те, що функція setValue () встановлює значення і випускається тільки в тому випадку, якщо value! = M_value. Це запобігає нескінченний цикл при циклічних сполуках (наприклад, якщо б b.valueChanged () був з'єднаний з a.setValue ()).

Сигнал випускається для кожного з'єднання, яке було створено, якщо сигнал з'єднаний з двома слотами, то він буде іспущен двічі. Також ви можете розірвати з'єднання за допомогою QObject :: disconnect ().

Даний приклад ілюструє спільну роботу об'єктів, які нічого не знають один про одного. Для її досягнення об'єкти повинні бути з'єднані за допомогою виклику простий функції QObject :: connect () або за допомогою функції uic'а - автоматичним зв'язуванням.

Препроцесор C + + замінює або видаляє ключові слова signals, slots і emit для того, щоб компілятору був наданий код, відповідний стандарту C++.

За допомогою moc обробляються визначення класів, що містять сигнали і слоти, і генеруються файли реалізації C + +, які будуть скомпільовані і пов'язані з іншими об'єктними файлами програми. Якщо ви використовуєте qmake, то в make-файл буде автоматично доданий виклик moc.

Сигнали випускаються об'єктом, коли змінюється його внутрішній стан, і якщо це може бути цікаво його клієнтам або власнику. Тільки класи, що містять визначення сигналів, і їх підкласи можуть випускати сигнали.

При випущенні сигналу слоти, з ним пов'язані, виконуються негайно, так само, як при звичайному виклику функції. Коли це трапляється, механізм сигналів і слотів повністю незалежний від циклу обробки подій графічного інтерфейсу користувача. Виконання коду, наступного за виразом emit продовжиться, як тільки завершиться виконання всіх слотів. У випадку з чергами сполук ситуація дещо відмінна, при цьому виконання коду, наступного за emit, продовжиться негайно, а слоти будуть виконані дещо пізніше.

Якщо кілька слотів пов'язані з одним сигналом, то при випущенні сигналу вони будуть виконані один за іншим у довільному порядку.

Сигнали автоматично генеруються утилітою moc, і ви не повинні включати їх реалізацію в. Cpp файли. Вони не повинні мати повертаються типів (тобто використовувати void).

Зауваження про аргументи: наш досвід показує, що сигнали і слоти більш придатні для повторного застосування, якщо вони не використовують спеціальних типів. Якщо сигнал QScrollBar :: valueChanged () повинен використовувати спеціальний тип, такий як гіпотетичний QScrollBar :: Range, він може бути з'єднаний лише з слотами, спроектованими спеціально для QScrollBar. Що-небудь настільки ж просте, як програма в частині 5 навчального посібника, буден неможливо реалізувати.

Слот викликається як тільки випускається з'єднаний з ним сигнал. Слоти - це звичайні функції C + +, вони можуть викликатися звичайним чином; їх єдина особливість - це те, що до них можуть бути приєднані сигнали.

Так як слоти є звичайними функціями-членами, вони мають права доступу, подібні звичайних функцій-членам. Разом з тим, як слотів вони можуть бути викликані будь-яким компонентом незалежно від рівня доступу за допомогою з'єднання сигнал-слот. Це означає, що сигнал, що випускається об'єктом довільного класу, може бути пов'язаний з закритим (private) слотом і бути викликаний в абсолютно стороннього класі.

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

У порівнянні із зворотними викликами, сигнали і слоти трохи повільніше у зв'язку з більшою гнучкістю, яку вони надають, але для реальних додатків це розходження неістотно. Взагалі, випускання сигналу, пов'язаного з деякими слотами, приблизно в десять разів повільніше, ніж виклик невіртуальної функції приймача безпосередньо. Так відбувається, тому що потрібно безпечно перебрати всі з'єднання (тобто перевірити, щоб наступні приймачі не були зруйновані під час випускання сигналу) і передати параметри покладеним чином. Хоча "десять викликів невіртуальний функцій" здається довгим, це менше ніж, наприклад, операція new або delete. Якщо ви обробляєте рядок, вектор або список, тобто операції, які вимагають виклику new або delete, обробка сигналів та слотів стають не найактивнішими споживачами часу.

Те ж саме відбувається, коли система викликає слот або побічно викликаються більше десятка функцій. На i586-500 ви можете генерувати близько 2,000,000 сигналів, пов'язаних з одним слотом, в секунду, або близько 1,200,000 сигналів, пов'язаних з двома слотами, в секунду. Простий і гнучкий механізм сигналів і слотів є гарною оболонкою для внутрішньої реалізації, яку користувачі навіть не помічатимуть.

Інші бібліотеки, що визначають змінні з ім'ям signals або slots, можуть викликати попередження і помилки при компіляції з додатком, створеним на основі Qt. Вирішити цю проблему може директива препроцесора # undef.

Мета-об'єктний компілятор (moc) переглядає декларацію класу у файлі C + + і генерує код, ініціалізувалися мета-об'єкт. Мета-об'єкт містить імена всіх сигналів і слотів і покажчики на їх функції.

Мета-об'єкт містить додаткову інформацію, таку як ім'я класу об'єкта. Також ви можете перевірити, чи є об'єкт спадкоємцем певного класу, наприклад:

if (widget-> inherits ("QAbstractButton")) {

QAbstractButton * button = static_cast <QAbstractButton *> (widget);

button-> toggle ();

}

Інформація мета-об'єкта також використовується в qobject_cast <T> (), який подібний QObject :: inherits (), але менш схильний до помилок:

if (QAbstractButton * button = qobject_cast <QAbstractButton *> (widget))

button-> toggle ();

Для отримання більш детальної інформації дивіться Система мета-об'єктів.

Далі наведено простий приклад віджету.

# Ifndef LCDNUMBER_H

# Define LCDNUMBER_H

# Include <QFrame>

class LcdNumber: public QFrame

{

Q_OBJECT

LcdNumber успадковує QObject, який використовує сигнали і слоти через QFrame і QWidget. Він трохи схожий на вбудований віджет QLCDNumber.

При розширенні препроцесором, макрос Q_OBJECT декларує кілька функцій-членів, які реалізуються moc; якщо ви отримали повідомлення про помилки компілятора, подібні "undefined reference to vtable for LcdNumber", ви, ймовірно, забули запустити moc або включити висновок moc в команду link.

public: LcdNumber (QWidget * parent = 0);

moc явно не вимагає цього, але якщо ви наслідуєте QWidget, майже напевно захочете мати аргумент parent у вашому конструкторі і передати його в конструктор базового класу.

Деякі деструктори і функції-члени тут опущені; moc ігнорує їх.

signals: void overflow ();

LcdNumber випускає сигнал, коли його просять показати невірне значення.

Якщо ви не дбаєте про те, чи виходить значення за встановлені межі, або вважаєте, що воно не може за них вийти, можете ігнорувати сигнал overflow (), тобто не з'єднувати з ним ні якої слот.

Якщо ви, навпаки, хочете викликати дві функції при виході значення за межі діапазону, з'єднайте сигнал з двома слотами. Qt викличе їх обидва (в довільному порядку).

public slots:

void display (int num);

void display (double num);

void display (const QString & str);

void setHexMode ();

void setDecMode ();

void setOctMode ();

void setBinMode ();

void setSmallDecimalPoint (bool point);

};

# Endif

Слот зазвичай використовується для отримання інформації про зміну стану інших віджетів. LcdNumber використовує цю можливість, код, наведений вище, показує, як відобразити змінене значення. Так як display () є частиною інтерфейсу між класом і рештою частини програми, то він є відкритим (public) слотом.

4.1 Розробка моделі для виведення і редагування даних

При створенні нової моделі для існуючої структури даних дуже важливо вирішити, який тип моделі найкраще підходить для забезпечення інтерфейсу до даних. Якщо структура даних може бути визначена як список або таблиця елементів, можна створити підклас QAbstractListModel або QAbstractTableModel, так як ці класи надають відповідні реалізації функцій за умовчанням.

Однак, якщо базова структура даних може бути представлена ​​тільки у вигляді ієрархічної деревоподібної структури, виникає необхідність у створенні підкласу QAbstractItemModel. Такий підхід показаний в прикладі Проста модель дерева.

У цьому розділі ми реалізуємо просту модель, засновану на списку рядків, для створення якої ідеальною основою є клас QAbstractListModel.

Безвідносно форми, яку приймає основна структура даних, хорошим тоном в спеціалізованих моделях є додавання стандартного API QAbstractItemModel до того, який надає більш природний доступ до структури даних. Це полегшує заповнення моделі даними, але крім того дозволяє іншим компонентам архітектури модель / уявлення взаємодіяти з моделлю, використовуючи стандартний API. Наведена нижче модель надає користувальницький конструктор виключно з цією метою.

4.1 Розробка моделі тільки-для-читання

Реалізована тут модель - це проста неієрархічні модель тільки-для-читання, заснована на стандартному класі QStringListModel. Вона має QStringList в якості внутрішнього сховища даних і реалізує лише найнеобхідніше для функціонування моделі. Для полегшення реалізації, ми створюємо підклас QAbstractListModel так як він визначає зручне поведінка за умовчанням для моделей списків і надає більш простий інтерфейс, ніж клас QAbstractItemModel.

При реалізації моделі слід пам'ятати, що QAbstractItemModel не зберігає даних, він лише надає інтерфейс, використовуваний уявленнями для доступу до даних. Для мінімальної моделі тільки-для-читання, необхідні реалізації лише декількох функцій, які надані за замовчуванням для більшості інтерфейсів. Декларація класу наступна:

class StringListModel: public QAbstractListModel

{

Q_OBJECT

public:

StringListModel (const QStringList & strings, QObject * parent = 0)

: QAbstractListModel (parent), stringList (strings) {}

int rowCount (const QModelIndex & parent = QModelIndex ()) const;

QVariant data (const QModelIndex & index, int role) const;

QVariant headerData (int section, Qt :: Orientation orientation,

int role = Qt :: DisplayRole) const;

private:

QStringList stringList;

};

Крім конструктора моделі, ми повинні реалізувати тільки дві функції: rowCount (), яка повертає кількість рядків у моделі, і data (), яка повертає елемент даних, що відповідає певному модельному індексу.

Добре працюють моделі також реалізують headerData () для отримання уявленнями дерев і таблиць чогось для відображення в їх заголовках.

Зверніть увагу на те, що це неієрархічні модель, тому ми не повинні турбуватися про батьківсько-дочірніх відносинах. Якщо наша модель ієрархічна, ми також повинні реалізувати функції index () і parent ().

Список рядків зберігається в закритій змінної-члені stringList.

Ми хочемо, щоб кількість рядків в моделі було таким же, що і кількість елементів у списку рядків. Пам'ятаючи про це, ми реалізуємо функцію rowCount ():

int StringListModel :: rowCount (const QModelIndex & parent) const

{

return stringList.count ();

}

Так як модель неієрархічні, ми можемо спокійно ігнорувати модельний індекс, відповідний батьківському елементу. За замовчуванням, моделі, похідні від QAbstractListModel, містять тільки один стовпець, тому нам не потрібно повторно реалізовувати функцію columnCount ().

Як елементи в поданні ми хочемо повернути рядки зі списку рядків. Функція data () відповідальна за повернення елемента даних, відповідного аргументу-індексу:

QVariant StringListModel :: data (const QModelIndex & index, int role) const

{

if (! index.isValid ())

return QVariant ();

if (index.row ()> = stringList.size ())

return QVariant ();

if (role == Qt :: DisplayRole)

return stringList.at (index.row ());

else

return QVariant ();

}

Якщо переданий модельний індекс валиден, номер рядка знаходиться в межах діапазону значень списку рядків і необхідна роль нами підтримується, ми повертаємо валідний QVariant.

Деякі вистави, такі як QTreeView і QTableView, можуть відображати заголовки поряд з елементами даних. Якщо наша модель відображається в поданні з заголовками, ми хочемо, щоб заголовки містили номери рядків і стовпців. Ми можемо надати інформацію про заголовках реалізувавши функцію headerData ():

QVariant StringListModel :: headerData (int section, Qt :: Orientation orientation,

int role) const

{

if (role! = Qt :: DisplayRole)

return QVariant ();

if (orientation == Qt :: Horizontal)

return QString ("Column% 1"). arg (section);

else

return QString ("Row% 1"). arg (section);

}

І знову ми повертаємо валідний QVariant тільки в тому випадку, якщо модельний індекс валиден і роль підтримується. При рішенні, що повинно бути повернуто, також приймається до уваги орієнтація заголовка.

Не всі уявлення відображають заголовки з елементами даних, і вони можуть бути налаштовані для приховування заголовків. Тим не менш, рекомендується реалізовувати функцію headerData () для надання важливої ​​інформації про дані, що надаються моделлю.

Елемент може мати кілька ролей, надаючи різні дані в залежності від зазначеної ролі. Елементи нашої моделі мають тільки одну роль, DisplayRole, так що ми повертаємо дані елемента незалежно від зазначеної ролі. Однак, дані, надані для ролі DisplayRole, ми може повторно використовувати в інших ролях, таких як ToolTipRole, яку уявлення можуть використовувати для відображення інформації про елемент в підказці.

ВИСНОВКИ

В даній дипломній роботі спроектовано та розроблено систему захисту інформації. Реалізовані функції кодування декодування інформації, спроектовано та розроблено ТСР сервер та два тестових клієнта. Алгоритм шифрування та перевірки данних на цілісність,достовірність не вцідображається на продуктивності программи. Створено зручний та інтуїтивно зрозумілий графічний інтерфейс користувача, що дає змогу користувачам з будь яким рівнем знань вільно користуватися даної ситемою. Програмний продукт є крос-платформним програмним забезпеченням, тобто може працювати з будь якою сучасною операційною системою, що робить його універсальним і майже незалежним від іншого програмного забезпечення.

СПИСОК ВИКОРИСТАНОЇ ЛІТЕРАТУРИ

  1. Закон України “Про охорону праці”

  2. Науково-практичний коментар до Закону України “Про охорону праці”, К. 1997 - 528 с.

  3. Автоматзированые информационные технологии в экономике. Учебник/ Под.ред.проф. Г.А. Титоренко. - М.: Компьютер, ЮНИТИ, 1998.- 400с.

  4. Береза А. Н. Основи створення інформаційних систем: Навч.посібник - К.: КНЕУ, 1998. - 140 с.

  5. Гужва В. М., Постєвой А. Г. Інформаційні системи в міжнародному бізнесі: Навч.посібник - К.: КНЕУ, 1999. - 164 с.

  6. Диго С.Н. Проектирование и использование базы даных: Учебник. - М.: Финансы и статистика, 1995.- 208 с.

  7. Евстигнеев Е.Н., Кавалев В.В. Автоматизированная система обработки економической информации в торговле: Учебник для торг. ВУЗОВ .- М.: Економика, 1991.- 272с.

  8. Єрьоміна Н. В. Проектування баз даних: Навч.посібник - К.: КНЕУ,1998. - 208с..

  9. Кондрашова С.С. Інформаційні технології в управлінні: Навч.посібник - К.: МАУП, 1998. - 136 с.

  10. Навакатікян О. О., Кальниш В. В. Охорона праці користувачів комп’ютерних відеодисплейних терміналів - К.: 1997. - 400 с.

  11. Рогач І. Ф, Сендзюк М. А. , Антонюк В. А. Інформаційні системи у фінансово - кредитних установах: Навч.посібник - К.: КНЕУ, 1999. - 216 с.

  12. Руденко В.Д., Макарчук О.М., Практичний курс інформатики/ За ред. Мадзігона В.М. - К.: Феникс, 1997.- 304 с.

  13. Ситник В. Ф., Краєва О. С. Технологія автоматизованої оброби економічної інформації: Навч.посібник - К.: КНЕУ, 1998. - 200 с.

  14. Сусиденко В Т. , Мирочник Г.Д. Применение автоматизированной системы управления в торговле - К.: Техника, 1989.-152с.

  15. Экономика торговли, Под.ред, Л.В. Бирюкова: Издательства “Экономика ” 1990. 421с.