Hálózati alkalmazások

Hasonló dokumentumok
Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Egységes és objektumközpontú adatbázis-kezelés (2. rész)

Eseménykezelés. Aszinkron kommunikáció

Számítógépes Hálózatok GY 3-4.hét

Kivételkezelés a C++ nyelvben Bevezetés

Programozás 6. Dr. Iványi Péter

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós május 6. Széchenyi István Egyetem, Gy r

Socket programozás Példák

Elemi alkalmazások fejlesztése III. A Qt assistant elindítása. Ajánlott ir odalom. A Qt assistant nyitó ablaka

MySql elindítása. Elemi alkalmazások fejlesztése IV. Feladat. Az alkalmazás adatbázisa

Számítógépes Hálózatok. 5. gyakorlat

Számítógépes Hálózatok. 4. gyakorlat

Számítógépes Hálózatok GY 4.hét

Elemi alkalmazások fejlesztése IV.

Konkurens TCP Szerver

Bevezetés Kiíratás Beolvasás Formázás Fájlkezelés Gyakorló feladatok C++ I/O. Bevezetés. Izsó Tamás február 20. Izsó Tamás C++ I/O / 1

Feladat. Tervezés és implementálás

Elemi alkalmazások fejlesztése III

Elemi alkalmazások fejlesztése III.

Rétegezett architektúra HTTP. A hálózatfejlesztés motorját a hálózati alkalmazások képezik. TCP/IP protokoll készlet

Tervezőeszközök, fejlesztőeszközök használata Qt alapú alkalmazásoknál. Saját vezérlő használata tervezőben (worldclocks)

Programozás II. ATM példa Dr. Iványi Péter

Informatika terméktervezőknek

Alkalmazások fejlesztése III. Qt 4 /C++ alapú grafikus alkalmazás Bevezetés I.

7. Laboratóriumi gyakorlat: Vezérlési szerkezetek II.

Dinamikus csatolású függvénykönyvtár készítése és használata Plugin-szerű betöltés Egyszeű C++ osztályok készítése

Számítógép labor V. Egyszer Web szerver. Dokumentáció. Készítette: Ács Gergely (K4C03M)

Eseménykezelés. Aszinkron kommunikáció

Webes alkalmazások fejlesztése 8. előadás. Webszolgáltatások megvalósítása (ASP.NET WebAPI)

Számítógépes Hálózatok. 3. gyakorlat

Nyíregyházi Egyetem Matematika és Informatika Intézete. Fájl rendszer

A függvény kód szekvenciáját kapcsos zárójelek közt definiáljuk, a { } -ek közti részt a Bash héj kód blokknak (code block) nevezi.

Számítógépes Hálózatok GY 6.hét

Hálózati architektúrák és Protokollok GI Kocsis Gergely

A C++ nyelvben a függvény nevek túlterhelésével biztonságosabbá tehetnénk az adatok kiírását és beolvasását.

A jobboldalon a pnlright egy Stacked Widget Állítsuk be az első lapot és nevezzük el pnldraw-ra:

Kommunikáció Androidon Mobilinternet Wifi

3D-s számítógépes geometria és alakzatrekonstrukció

Tartalom DCOM. Történeti áttekintés. Történeti áttekintés. Történeti áttekintés. Történeti áttekintés

Hálózatkezelés. Tóth Zsolt. Miskolci Egyetem. Tóth Zsolt (Miskolci Egyetem) Hálózatkezelés / 20

QLabel *label = new Qlabel("Hello Qt!",0);

Programozás II. 2. Dr. Iványi Péter

Számítógépes Hálózatok GY 7.hét

Alkalmazások fejlesztése III. Qt 4 /C++ alapú MDI alkalmazás: Számlakészítő program 1/3

Programozás I. 5. Előadás: Függvények

Elemi alkalmazások fejlesztése IV. Adatbáziskezel alkalmazás készítése QtDesignerben. Készítette: Szabóné Nacsa Rozália

Bevezetés a programozásba II. 5. Előadás: Másoló konstruktor, túlterhelés, operátorok

API tervezése mobil környezetbe. gyakorlat

Java Programozás 9. Gy: Java alapok. Adatkezelő 5.rész

11. Gyakorlat: Certificate Authority (CA), FTP site-ok

Szkriptnyelvek. 1. UNIX shell

Eseményvezérelt alkalmazások fejlesztése I 8. előadás. Adatbázis-kezelés modell/nézet architektúrában

Alkalmazások fejlesztése III. Qt 4 /C++ alapú MDI alkalmazás: Számlakészítő program 2/3

Pick Pack Pont kereső és boltválasztó alkalmazás

Objektum Orientált Programozás. 11. Kivételkezelés 44/1B IT MAN

Pénzügyi algoritmusok

Az állományok kezelésére használt fontosabb parancsok

Mobil informatika gyakorlat. 2. óra: NFC a gyakorlatban

Szövegek C++ -ban, a string osztály

Programozás C nyelven (3. ELŐADÁS) Sapientia EMTE

OAF Gregorics Tibor: Minta dokumentáció a 3. házi feladathoz 1.

Budapest, március. ELTE Informatikai Kar

osztályok kapcsolata Származtatatás C++ Izsó Tamás március 19. Izsó Tamás Származtatatás/ 1

KIRA. KIRA rendszer. Telepítési útmutató v1

CREATE TABLE student ( id int NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name varchar(100) NOT NULL, address varchar(100) NOT NULL )

Eseményvezérelt alkalmazások fejlesztése I 10. előadás. Adatbázis-kezelés modell/nézet architektúrában. Giachetta Roberto

Kiszolgálók üzemeltetése FTP. Iványi Péter

Programozási alapismeretek :: beadandó feladat. Felhasználói dokumentáció. Molnár Tamás MOTIABT.ELTE

Objektum elvű alkalmazások fejlesztése Kifejezés lengyel formára hozása és kiértékelése

1. Gyakorlat: Telepítés: Windows Server 2008 R2 Enterprise, Core, Windows 7

Pénzügyi algoritmusok

Bevezetés a programozásba Előadás: Objektumszintű és osztályszintű elemek, hibakezelés

WEBFEJLESZTÉS 2. ADATBÁZIS-KEZELÉS, OSZTÁLYOK

ProFTPD. Molnár Dániel október oldal

A belső hálózat konfigurálása

Elemi alkalmazások fejlesztése III

Számítógépes Hálózatok. 7. gyakorlat

Java Programozás 4. Gy: Java GUI. Tipper, MVC kalkulátor

Elemi alkalmazások fejlesztése I. Olvassunk be egy fájlból egész számokat egy tömbbe. Keressük meg a tömb valamely

C++ programozási nyelv Struktúrák a C++ nyelvben Gyakorlat

ISA szimulátor objektum-orientált modell (C++)

Az SQL*Plus használata

Számítógépes hálózatok

BioAdmin 4.1 könnyű telepítés csak Kliens használatra

Teleoperáció Robot vezérlése IP-hálózaton

Elemi alkalmazások fejlesztése IV. Adatbázis-kezelő GUI alkalmazás készítése 3. Összetett tábla karbantartása

Elemi alkalmazások fejlesztése III.

Hálózati architektúrák és Protokollok GI Kocsis Gergely

SQL*Plus. Felhasználók: SYS: rendszergazda SCOTT: demonstrációs adatbázis, táblái: EMP (dolgozó), DEPT (osztály) "közönséges" felhasználók

LINUX PMB LINUXOS PARANCSOK ÉS HASZNÁLATUK - GRUB

Johanyák Zsolt Csaba: Ugráló gomb oktatási segédlet Copyright 2008 Johanyák Zsolt Csaba

Java és web programozás

MicroSigner Közvetítő Szerver fejlesztői dokumentáció

20. Tétel 1.0 Internet felépítése, OSI modell, TCP/IP modell szintjenek bemutatása, protokollok Pozsonyi ; Szemenyei

Architektúra, megszakítási rendszerek

II. Mérés SZÉCHENYI ISTVÁN EGYETEM GYŐR TÁVKÖZLÉSI TANSZÉK

Átírás:

Hálózati alkalmazások

Hálózati alkalmazások QT osztályai A Qt támogatja az FTP és HTTP alapú hálózati alkalmazások készítését. A QFtp osztály segítségével lehet fájlokat megadott hálózati helyekre fel- vagy helyekről letölteni. A QHttp osztály felhasználásával web szerverek számára lehet kéréseket megfogalmazni és az azokra kapott válaszokat feldolgozni. A Qt az alacsony szintű hálózat-kezeléshez a QTcpSocket és a QUdpSocket osztályokat biztosítja, amelyek a TCP és UDP protokollokat implementálják. Mindkettő alkalmas hálózati kliens-szerver alkalmazások létrehozására. Az alkalmazások.pro fájljában szükség van az alábbi kapcsolóra: QT += network 2

FTP kliens A QFtp osztály az FTP protokoll kliens oldali implementációját adja. Különféle metódusokat biztosít az FTP parancsok végrehajtásához. A connecttohost(), login(), close(), list(), cd(), get(), put(), remove(), mkdir(), rmdir(), rename() metódusok mindegyike egy FTP parancsot vált ki, és visszaadja az FTP parancs azonosítóját. Bármely más FTP parancs a rawcommand() metódus segítségével kiadható ftp.rawcommand("site CHMOD 755 fortune"); A QFtp kiváltja a commandstarted(int) szignált, amikor egy parancsot el kezd végrehajtani, és a commandfinished(int, bool) szignált, amikor egy parancs befejeződött. Az int paraméter a parancs azonosítója. A QFtp osztály az FTP parancsok aszinkron működését támogatja. Amikor az összes befejeződik az összes kérés, kiváltja a done(bool) szignált. 3

1.Feladat Készítsünk egy olyan alkalmazást, amely segítségével egy távoli fájlt tudunk letölteni FTP protokollt használva. A program legyen egy konzol alkalmazás. nincs szükség a QtGui könyvtárra int main(int argc, char *argv[]){ QCoreApplication app(argc, argv); parancssor argumentumai QStringList args = app.arguments(); if (args.count()!= 2) { cerr << "Usage: ftpget url" << endl << "Example:" << endl << " ftpget ftp://ftp.trolltech.com/mirrors" << endl; return 1; saját osztály elindítja a fájl-letöltés FtpGet getter; if (!getter.getfile(qurl(args[1]))) return 1; QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit())); return app.exec(); a fájl-letöltés befejezése leállítja az alkalmazást 4

1.Feladat: tervezés FtpGet QObject - _ftp :QFtp - _file :QFile + FtpGet(QObject*) + getfile(qurl) «slot» - ftpdone(bool) 5

1.Feladat: megoldás FtpGet::FtpGet(QObject *parent) : QObject(parent){ connect(&_ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool))); void FtpGet::ftpDone(bool error){ fájl művelet befejezésének lekezelése if (error) { cerr << "Error: " << qprintable(_ftp.errorstring()) << endl; else { cerr << "File downloaded as " << qprintable(_file.filename()) << endl; _file.close(); emit done(); 6

1.Feladat: megoldás bool FtpGet::getFile(const QUrl &url){ if (!url.isvalid()) { URL ellenőrzése cerr << "Error: Invalid URL" << endl; return false; if (url.scheme()!= "ftp") { cerr << "Error: URL must start with 'ftp:'" << endl; return false; if (url.path().isempty()) { cerr << "Error: URL has no path" << endl; return false; 7

1.Feladat: megoldás bool FtpGet::getFile(const QUrl &url){ QString localfilename = QFileInfo(url.path()).fileName(); if (localfilename.isempty()) localfilename = "ftpget.out"; _file.setfilename(localfilename); if (!_file.open(qiodevice::writeonly)) { lokális fájl nevének beállítása cerr << "Error: Cannot open " << qprintable(_file.filename()) << " for writing: " << qprintable(_file.errorstring()) << endl; return false; lokális fájl megnyitása _ftp.connecttohost(url.host(), url.port(21)); _ftp.login(); _ftp.get(url.path(), &_file); FTP műveletek _ftp.close(); return true; 8

2.Feladat Készítsünk egy olyan command-line alkalmazást, amely minden fájlt letölt egy FTP könyvtárból, sőt rekurzív módon annak alkönyvtáraiból is. int main(int argc, char *argv[]) nincs szükség a QtGui könyvtárra { QCoreApplication app(argc, argv); parancssor argumentumai QStringList args = app.arguments(); if (args.count()!= 2) { cerr << "Usage: spider url" << endl << "Example:" << endl << "spider ftp://ftp.trolltech.com/freebies/leafnode" << endl; return 1; saját osztály elindítja a fájl-letöltés Spider spider; if (!spider.getdirectory(qurl(args[1]))) return 1; QObject::connect(&spider, SIGNAL(done()), &app, SLOT(quit())); return app.exec(); a fájl-letöltés befejezése leállítja az alkalmazást 9

2.Feladat: tervezés Spider - _ftp :QFtp - _pendingdirs : QString - _openedfiles : Qlist<Qfile*> - _currentdir : QString - _currentlocaldir : QString + Spider(QObject*) + getdirectory(qurl) - processnextdirectory() «signal» - done() «slot» - ftpdone(bool) - ftplistinfo(qurlinfo) QObject letöltésre váró könyvtárak nevei memória szivárgás elkerüléséhez ezt az FTP get műveletével elkezdett letöltés befejezése váltja ki connect(&_ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool))); connect(&_ftp, SIGNAL(listInfo(const QUrlInfo &)), this, SLOT(ftpListInfo(const QUrlInfo &))); ezt az FTP list művelete minden egyes listázott tételre kiváltja 10

2.Feladat: megoldás bool Spider::getDirectory(const QUrl &url) { if (!url.isvalid()) { ez indítja az adott könyvtárbeli fájlok letöltését cerr << "Error: Invalid URL" << endl; return false; if (url.scheme()!= "ftp") { cerr << "Error: URL must start with 'ftp:'" << endl; return false; _ftp.connecttohost(url.host(), url.port(21)); _ftp.login(); QString path = url.path(); if (path.isempty()) path = "/"; _pendingdirs.append(path); processnextdirectory(); return true; 11

2.Feladat: megoldás void Spider::processNextDirectory() { if (!_pendingdirs.isempty()) { _currentdir = _pendingdirs.takefirst(); _currentlocaldir = "downloads/" + _currentdir; QDir(".").mkpath(_currentLocalDir); _ftp.cd(_currentdir); _ftp.list(); else { emit done(); Ha van már fellelt, de feldolgozatlan könyvtár, akkor annak elemeit listázza, és mindegyikre kiváltja a listinfo(qurlinfo) szignált. 12

2.Feladat: megoldás void Spider::ftpListInfo(const QUrlInfo &urlinfo) { valahányszor egy könyvtárbeli if (urlinfo.isfile()) { tétel listázásra kerül if (urlinfo.isreadable()) { QFile *file = new QFile(_currentLocalDir +"/"+ urlinfo.name()); if (!file->open(qiodevice::writeonly)) { cerr << "Warning: Cannot open file " << qprintable(qdir::convertseparators(file->filename())) << endl; return; _ftp.get(urlinfo.name(), file); _openedfiles.append(file); ha normális fájl, akkor elkezdjük a letöltését else if (urlinfo.isdir() &&!urlinfo.issymlink()) { _pendingdirs.append(_currentdir + "/" + urlinfo.name()); ha könyvtár, akkor feljegyezzük 13

2.Feladat: megoldás void Spider::ftpDone(bool error) { if (error) { cerr << "Error: " << qprintable(_ftp.errorstring()) << endl; else { cout << "Downloaded " << qprintable(_currentdir) << " to " << qprintable(qdir::convertseparators( QDir(_currentLocalDir).canonicalPath())); qdeleteall(_openedfiles); _openedfiles.clear(); processnextdirectory(); itt van a rekurzió amikor az eddig elindított fájl letöltések befejeződtek Eltároltuk az eddig letöltésre kijelölt fájlokat, ezért most a letöltések befejeződésekor törölni tudjuk őket, így elkerüljük a memória szivárgást. 14

HTTP kliens A QHttp osztály a HTTP protokoll kliens oldali implementációját adja. Különféle metódusokat biztosít az FTP parancsok végrehajtásához. A sethost(), get(), post(), remove(), head() metódusok mindegyike egy HTTP parancsot vált ki. Bármely más FTP parancs a rawcommand() metódus segítségével kiadható ftp.rawcommand("site CHMOD 755 fortune"); A QHttp kiváltja a requeststarted(int) szignált, amely egy kérés végrehajtásakor keletkezik, és a requestfinished(int, bool) szignált, amikor a kérés befejeződött. Az int paraméter a kérés azonosítója. Amikor a kérések sora kiürül, akkor kiváltódik a done(bool) szignál. 15

3.Feladat Készítsünk egy olyan alkalmazást, amely segítségével egy távoli fájlt tudunk letölteni HTTP protokollt használva. A program legyen egy konzol alkalmazás. nincs szükség a QtGui könyvtárra int main(int argc, char *argv[]){ QCoreApplication app(argc, argv); parancssor argumentumai QStringList args = app.arguments(); if (args.count()!= 2) { cerr << "Usage: httpget url" << endl << "Example:" << endl << "httpget http://doc.trolltech.com/qq/index.html" << endl; return 1; saját osztály elindítja a fájl-letöltés HttpGet getter; if (!getter.getfile(qurl(args[1]))) return 1; QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit())); return app.exec(); a fájl-letöltés befejezése leállítja az alkalmazást 16

3.Feladat: tervezés HttpGet QObject - _http :QHttp - _file :QFile + HttpGet(QObject*) + getfile(qurl) «signal» - done() «slot» - httpdone(bool) 17

3.Feladat: megoldás HttpGet::HttpGet(QObject *parent) : QObject(parent){ connect(&_http, SIGNAL(done(bool)), this, SLOT(httpDone(bool))); fájl művelet befejezésének lekezelése void HttpGet::httpDone(bool error){ if (error) { cerr << "Error: " << qprintable(_http.errorstring()) << endl; else { cerr << "File downloaded as " << qprintable(_file.filename()) << endl; _file.close(); emit done(); 18

3.Feladat: megoldás bool HttpGet::getFile(const QUrl &url){ if (!url.isvalid()) { URL ellenőrzése cerr << "Error: Invalid URL" << endl; return false; if (url.scheme()!= "http") { cerr << "Error: URL must start with 'http:'" << endl; return false; if (url.path().isempty()) { cerr << "Error: URL has no path" << endl; return false; 19

3.Feladat: megoldás bool HttpGet::getFile(const QUrl &url){ QString localfilename = QFileInfo(url.path()).fileName(); if (localfilename.isempty()) localfilename = "httpget.out"; _file.setfilename(localfilename); lokális fájl nevének beállítása if (!_file.open(qiodevice::writeonly)) { cerr << "Error: Cannot open " << qprintable(_file.filename()) << " for writing: " << qprintable(_file.errorstring()) << endl; return false; lokális fájl megnyitása _http.sethost(url.host(), url.port(80)); _http.get(url.path(), &_file); _http.close(); HTTP műveletek return true; 20

TCP kliens-szerver alkalmazás A QTcpSocket és QTcpServer osztályok a TCP kliensek és szerverek implementációját adják. A TCP egy adatfolyam-orientált protokoll. A TCP-re épülő magasabb szintű protokollok tipikusan vagy sor-, vagy blokk-orientáltak. A sor-orientált protokollok soronként visznek át egy szöveget. A blokk-orientált protokollok bináris adatblokkokban. A QTcpSocket egy QDataStream vagy egy QTextStream felhasználásával végez írást illetve olvasás. A hálózatról történő olvasás esetén arra kell ügyelni, hogy szemben a szokásos fájlból olvasással a >> operator használata előtt meg kell győződni arról, hogy elegendő adatot fogunk-e letölteni. 21

4.Feladat Készítsünk egy utazást tervező alkalmazást. A Trip Planner kliens segítségével a felhasználó egy vonatútját tudja megtervezni. A Trip Server utazási információt nyújt a kliens számára az adott ország vasúti menetrendjéről. 22

4.Feladat: főprogramok int main(int argc, char *argv[]){ QApplication app(argc, argv); TripServer server; int main(int argc, char *argv[]){ QApplication app(argc, argv); TripPlanner tripplanner; tripplanner.show(); return app.exec(); if(!server.listen(qhostaddress::any, 6178)){ cerr << "Failed to bind to port" << endl; return 1; QPushButton quitbutton(tr("&quit")); quitbutton.setwindowtitle(tr("trip Server")); Connect(&quitButton, SIGNAL(clicked()), &app, SLOT(quit())); quitbutton.show(); return app.exec(); 23

4.Feladat: kliens tervezés Qdialog, Ui::TripPlanner TripPlanner - _tcpsocket :QTcpSocket - _nextblocksize :qint16 + TripPlanner(QWidget*) - closeconnection() «slot» - connecttoserver() - stopsearch() - updatetablewidget() - sendrequest() - connectionclosedbyserver() - error() felület két gombjának eseménykezelői szoket szignálok eseménykezelői 24

4.Feladat: kliens megoldás TripPlanner::TripPlanner(QWidget *parent): QDialog(parent) { setupui(this); QDateTime datetime = QDateTime::currentDateTime(); felület konfigurálása dateedit->setdate(datetime.date()); timeedit->settime(qtime(datetime.time().hour(), 0)); progressbar->hide(); progressbar->setsizepolicy(qsizepolicy::preferred,qsizepolicy::ignored); tablewidget->verticalheader()->hide(); tablewidget->setedittriggers(qabstractitemview::noedittriggers); connect(searchbutton,signal(clicked()), this, SLOT(connectToServer())); connect(stopbutton, SIGNAL(clicked()), this, SLOT(stopSearch())); connect(&_tcpsocket, SIGNAL(connected()), this, SLOT(sendRequest())); connect(&_tcpsocket, SIGNAL(disconnected()), this, SLOT(connectionClosedByServer())); connect(&_tcpsocket, SIGNAL(readyRead()), this, SLOT(updateTableWidget())); connect(&_tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error())); eseménykezelés 25

4.Feladat: kliens megoldás void TripPlanner::connectToServer() { _tcpsocket.connecttohost(" ", 6178); Vagy kiváltja a connected() szignált, és elindítja a sendrequest()-t kezelőt, vagy az error()-t. a Search gomb aszinkron módon indítja el a kapcsolatépítést; a kapcsolat majd később áll fel konkrét cím helyett a kipróbáláskor QHostAddress::LocalHost-ot használjuk tablewidget->setrowcount(0); searchbutton->setenabled(false); stopbutton->setenabled(true); statuslabel->settext(tr("connecting to server...")); progressbar->show(); A szervertől fogadott soron következő blokk hosszát még nem ismerjük. _nextblocksize = 0; 26

4.Feladat: TCP kérés formája A szerver felé megfogalmazunk egy blokként egy kérést QByteArray bináris formában, amely az alábbiakat tartalmazza: típus quint16 quint8 QString QString QDate QTime quint8 jelentés Blokk mérete byte-okban a blokkméret nélkül Kérés típusa (mindig S ) Indulási állomás Érkezési állomás Utazás dátuma Becsült utazási idő Az indulás ( D ) vagy érkezés ( A ) időpontja 27

4.Feladat: kliens megoldás Search gomb elindítja void TripPlanner::sendRequest() a keresést { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setversion(qdatastream::qt_4_1); out << quint16(0) << quint8('s') << fromcombobox->currenttext() << tocombobox->currenttext() << dateedit->date() << timeedit->time(); if (departureradiobutton->ischecked()) out << quint8('d'); else out << quint8('a'); out.device()->seek(0); out << quint16(block.size() - sizeof(quint16)); _tcpsocket.write(block); statuslabel->settext(tr("sending request...")); 28

4.Feladat: szerver válasza A szerver blokk-sorozatként küldi a választ: 51 adatok 48 adatok 58 adatok 0xFFFF Egy blokk formája: 51 byte 48 byte 58 byte típus quint16 QDate QTime quint16 quint8 QString jelentés Blokk mérete byte-okban a blokkméret nélkül Indulási dátum Indulási időpont Utazási idő Átszállások száma Vonat típusa 29

4.Feladat: kliens megoldás void TripPlanner::updateTableWidget() { QDataStream in(&_tcpsocket); in.setversion(qdatastream::qt_4_1); forever { int row = tablewidget->rowcount(); if (_nextblocksize == 0) { if (_tcpsocket.bytesavailable() < sizeof(quint16)) break; in >> _nextblocksize; if (_nextblocksize == 0xFFFF) { closeconnection(); statuslabel->settext(tr("found %1 trip(s)").arg(row)); break; if (_tcpsocket.bytesavailable() < _nextblocksize) break; 30

4.Feladat: megoldás forever { QDate date; QTime departuretime, arrivaltime; quint16 duration, changes; QString traintype; in >> date >> departuretime >> duration >> changes >> traintype; arrivaltime = departuretime.addsecs(duration * 60); tablewidget->setrowcount(row + 1); QStringList fields; fields << date.tostring(qt::localdate) << departuretime.tostring(tr("hh:mm")) << arrivaltime.tostring(tr("hh:mm")) << tr("%1 hr %2 min").arg(duration / 60).arg(duration % 60) << QString::number(changes) << traintype; for (int i = 0; i < fields.count(); ++i) tablewidget->setitem(row, i, new QTableWidgetItem(fields[i])); _nextblocksize = 0; 31

4.Feladat: kliens megoldás void TripPlanner::stopSearch(){ statuslabel->settext(tr("search stopped")); closeconnection(); amikor a kliens a Stop gombbal megszakítja a kapcsolatot void TripPlanner::connectionClosedByServer(){ ha a szerver lezárja a kapcsolat, de nem if (_nextblocksize!= 0xFFFF) kaptuk meg az end-of-data jelet. statuslabel->settext(tr("error: Connection closed by server")); closeconnection(); void TripPlanner::error(){ sikertelen kapcsolat indítás esetén statuslabel->settext(_tcpsocket.errorstring()); closeconnection(); void TripPlanner::closeConnection(){ _tcpsocket.close(); searchbutton->setenabled(true); stopbutton->setenabled(false); progressbar->hide(); a szoket lezárása, felület módosítása 32

3.Feladat: szerver tervezés TripServer QTcpServer ClientSocket - _nextblocksize :qint16 QTcpSocket + TripServer(QObject*) - incomingconnection(socketid : int) + ClientSocket(QObject*) - generaterandomtrip( ) «slot» - readclient() skip ClientSocket *socket = new ClientSocket(this); socket->setsocketdescriptor(socketid); 33

4.Feladat: szerver megoldás ClientSocket::ClientSocket(QObject *parent) : QTcpSocket(parent) { connect(this, SIGNAL(readyRead()), this, SLOT(readClient())); connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); _nextblocksize = 0; A klienstől fogadott soron következő blokk hosszát még nem ismerjük. 34

4.Feladat: szerver megoldás void ClientSocket::readClient() ha üzenet érkezett a klienstől { QDataStream in(this); in.setversion(qdatastream::qt_4_1); if (_nextblocksize == 0) { if (bytesavailable() < sizeof(quint16)) return; in >> _nextblocksize; if (bytesavailable() < _nextblocksize) return; quint8 requesttype; QString from, to; QDate date; QTime time; quint8 flag; 35

4.Feladat: szerver megoldás in >> requesttype; if (requesttype == 'S') { in >> from >> to >> date >> time >> flag; srand(from.length() * 3600 + to.length() * 60 + time.hour()); int numtrips = rand() % 8; for (int i = 0; i < numtrips; ++i) generaterandomtrip(from, to, date, time); QDataStream out(this); a válasz generálása out << quint16(0xffff); close(); 36

4.Feladat: szerver megoldás A valódi szerver mock-olása void ClientSocket::generateRandomTrip(const QString & /* from */, const QString & /* to */, const QDate &date, const QTime &time) { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setversion(qdatastream::qt_4_1); quint16 duration = rand() % 200; out << quint16(0) << date << time << duration << quint8(1) << QString("InterCity"); out.device()->seek(0); out << quint16(block.size() - sizeof(quint16)); write(block); 37