abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    včera 17:11 | Nová verze

    Byl vydán Nextcloud Hub 8. Představení novinek tohoto open source cloudového řešení také na YouTube. Vypíchnout lze Nextcloud AI Assistant 2.0.

    Ladislav Hagara | Komentářů: 0
    včera 13:33 | Nová verze

    Vyšlo Pharo 12.0, programovací jazyk a vývojové prostředí s řadou pokročilých vlastností. Krom tradiční nadílky oprav přináší nový systém správy ladících bodů, nový způsob definice tříd, prostor pro objekty, které nemusí procházet GC a mnoho dalšího.

    Pavel Křivánek | Komentářů: 5
    včera 04:55 | Zajímavý software

    Microsoft zveřejnil na GitHubu zdrojové kódy MS-DOSu 4.0 pod licencí MIT. Ve stejném repozitáři se nacházejí i před lety zveřejněné zdrojové k kódy MS-DOSu 1.25 a 2.0.

    Ladislav Hagara | Komentářů: 33
    25.4. 17:33 | Nová verze

    Canonical vydal (email, blog, YouTube) Ubuntu 24.04 LTS Noble Numbat. Přehled novinek v poznámkách k vydání a také příspěvcích na blogu: novinky v desktopu a novinky v bezpečnosti. Vydány byly také oficiální deriváty Edubuntu, Kubuntu, Lubuntu, Ubuntu Budgie, Ubuntu Cinnamon, Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio, Ubuntu Unity a Xubuntu. Jedná se o 10. LTS verzi.

    Ladislav Hagara | Komentářů: 13
    25.4. 14:22 | Komunita

    Na YouTube je k dispozici videozáznam z včerejšího Czech Open Source Policy Forum 2024.

    Ladislav Hagara | Komentářů: 2
    25.4. 13:22 | Nová verze

    Fossil (Wikipedie) byl vydán ve verzi 2.24. Jedná se o distribuovaný systém správy verzí propojený se správou chyb, wiki stránek a blogů s integrovaným webovým rozhraním. Vše běží z jednoho jediného spustitelného souboru a uloženo je v SQLite databázi.

    Ladislav Hagara | Komentářů: 0
    25.4. 12:44 | Nová verze

    Byla vydána nová stabilní verze 6.7 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 124. Přehled novinek i s náhledy v příspěvku na blogu. Vypíchnout lze Spořič paměti (Memory Saver) automaticky hibernující karty, které nebyly nějakou dobu používány nebo vylepšené Odběry (Feed Reader).

    Ladislav Hagara | Komentářů: 0
    25.4. 04:55 | Nová verze

    OpenJS Foundation, oficiální projekt konsorcia Linux Foundation, oznámila vydání verze 22 otevřeného multiplatformního prostředí pro vývoj a běh síťových aplikací napsaných v JavaScriptu Node.js (Wikipedie). V říjnu se verze 22 stane novou aktivní LTS verzí. Podpora je plánována do dubna 2027.

    Ladislav Hagara | Komentářů: 0
    25.4. 04:22 | Nová verze

    Byla vydána verze 8.2 open source virtualizační platformy Proxmox VE (Proxmox Virtual Environment, Wikipedie) založené na Debianu. Přehled novinek v poznámkách k vydání a v informačním videu. Zdůrazněn je průvodce migrací hostů z VMware ESXi do Proxmoxu.

    Ladislav Hagara | Komentářů: 0
    25.4. 04:11 | Nová verze

    R (Wikipedie), programovací jazyk a prostředí určené pro statistickou analýzu dat a jejich grafické zobrazení, bylo vydáno ve verzi 4.4.0. Její kódové jméno je Puppy Cup.

    Ladislav Hagara | Komentářů: 0
    KDE Plasma 6
     (74%)
     (9%)
     (2%)
     (16%)
    Celkem 806 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

    Konzolové programy v Qt 4 – 3 (TCP server)

    16. 9. 2009 | David Watzke | Programování | 6701×

    V tomto díle si ukážeme, jak za použití modulu QtNetwork naprogramovat jednoduchý TCP server.

    Tento díl seriálu úzce souvisí s článkem Grafické programy v Qt 4 – 8 (TCP klient), jelikož je o server, jehož klienta jsem napsal s grafickým rozhraním. Základní informace o TCP síťování, socketech v Qt a ukázkovém programu se dočtete tam, zatímco tento článek popisuje čistě serverovou část, takže doporučuji začít čtení odkazovaným článkem.

    TCP server

    Teď, když chápeme komunikaci přes QTcpSocket, můžeme se vrhnout na serverovou část. Základem je třída QTcpServer. Hned po vytvoření instance je vhodné nastavit nějaké základní parametry serveru, například takto:

    QTcpServer* server = new QTcpServer(this);
    // explicitně zakážeme použití proxy
    server->setProxy(QNetworkProxy::NoProxy);
    // nastavíme max. počet spojení
    server->setMaxPendingConnections(50);
    

    Ve většině případů je dobré zpracovat signál newConnection(), kterým nás server informuje o novém příchozím spojení. Slot, který na tento signál napojíme, bude chtít nejspíš získat socket tohoto nového spojení. K tomu využijeme metodu nextPendingConnection(), a to následovně:

    // získáme socket
    QTcpSocket* socket = server->nextPendingConnection();
    // dobré je hned ověřit, zda ještě existuje (tj. zda metoda nevrátila 0)
    if(!socket)
    	return;
    

    Existují dvě alternativy k tomuto přístupu zpracování nových příchozích spojení a jejich použití záleží na tom, čeho přesně chcete dosáhnout. Pokud potřebujete provádět něco velmi specifického a vyžadujete vysokou flexibilitu, potom si celou událost můžete zpracovat sami, a to tak, že si vytvoříte vlastní třídu založenou na QTcpServer a reimplementujete její chráněnou virtuální metodu incomingConnection(int socketDescriptor). Integer, který dostanete jako argument, je popisovač (descriptor) socketu a pokud nepoužíváte QNetworkProxy, lze s ním pracovat pomocí nativních socketových funkcí.

    Druhý alternativní způsob je podstatně jednodušší. Nejdřív je třeba spustit server (viz níže) a potom lze použít blokující metodu waitForNewConnection(), které lze zadat čas v milisekundách (jak dlouho má čekat na příchozí připojení) a ukazatel na bool, do kterého se uloží informace o tom, zda došlo k vypršení času (tedy false znamená, že máte nové spojení).

    Když máme připravené zpracování nových připojení, můžeme spustit server, tedy naslouchání na určité adrese (nebo více adresách) a portu. Třeba takto:

    QString ip("127.0.0.1");
    
    QHostAddress addr;
    if(!addr.setAddress(ip))
    { // zadaná IP adresa není ve správném formátu
    	return 1;
    }
    
    // port=0 zajistí automatický výběr portu
    server->listen(addr, 0);
    

    TODO server

    Ještě než server spustíte, je třeba vytvořit mu konfigurační soubor, kam zapíšete platná uživatelská jména (bez mezer) a přiřadíte jim hesla (resp. jejich SHA1 hash). Chcete-li vytvořit uživatele user s heslem pass, tak si nejdřív zjistěte SHA1 hash řetězce „pass“:

    $ echo -n "pass" | sha1sum
    9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684
    

    Když máte hash, vytvořte si konfigurační soubor v textovém editoru (na UNIXech ~/.config/watzke.cz/todoserver.conf) a přidejte do něj sekci [logins] a vaším uživatelem.

    [logins]
    user=9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684
    

    Server komunikuje jednoduchým protokolem, který je zdokumentovaný ve výše odkazovaném článku. Obsahuje jednoduchou obranu před bruteforce přihlašováním – povolí maximálně 10 chybných přihlášení za minutu. Jde spíše jen o ukázku implementace takové věci, spíš než cokoliv jiného, nicméně crackera by to mělo zpomalit :-)

    Samozřejmě teď lze namítnout, že zmiňovat crackery je výsměch, když nepoužívám SSL sockety (nebo jiný způsob šifrování), ale o to mi v této ukázce nejde. Nicméně, když najdete bezpečnostní chybu, která s tímto nesouvisí, určitě se ozvěte v diskusi. Ještě dodám, že o chybějícím limitu délky jednotlivých záznamů vím, může tam být (teoreticky) libovolně dlouhý řetězec, i když můj klient umožní max. 32767 (2^15-1) znaků. Sám jsem několik bezpečnostních chyb odhalil a opravil při testování. Zvlášť při psaní síťového serveru, kde se řeší přihlašování, je třeba korektně ošetřovat nejrůznější výjimky. Nikdy nespoléhejte pouze na kontroly ve vašem klientovi.

    tcpserver.h: API.

    #ifndef TCPSERVER_H
    #define TCPSERVER_H
    
    #include <QObject>
    #include <QTextStream>
    #include <QList>
    #include <QPair>
    #include <QHostAddress>
    #include <QHash>
    #include <QSettings>
    
    class QTcpServer;
    class QTcpSocket;
    
    class TcpServer : public QObject
    {
    	Q_OBJECT
    public:
    	TcpServer(QHostAddress addr = QHostAddress(QHostAddress::Any),
    		  int port = 2266);
    
    private:
    	QTcpServer* server;
    	QTextStream cerr;
    	QHash<QTcpSocket*, QString> logins;
    	QHash<QString, int> log;
    
    	QSettings settings;
    
    	void login(QTcpSocket* socket, const QString& user, const QString& pass,
    		   bool force = false);
    	QString getKey(QString user, int index);
    	void sortKeys(QString user);
    
    	void listItems(QTcpSocket* socket);
    	void addItem(QTcpSocket* socket, QString item);
    	void removeItems(QTcpSocket* socket, QList<QByteArray> keys);
    
    	void socketWrite(QTcpSocket* socket, QByteArray data);
    
    private slots:
    	void purgeLog();
    	void handleNewConnection();
    	void reply();
    	void gotDisconnected();
    };
    
    #endif // TCPSERVER_H
    

    tcpserver.cpp:

    #include "tcpserver.h"
    
    #include <QtNetwork>
    #include <cstdio>
    
    TcpServer::TcpServer(QHostAddress addr, int port)
    	: cerr(stderr, QIODevice::WriteOnly) // poslouží pro výpis na std. chybový výstup,
    					     // podobně jako std::cerr v C++
    {
    	// vytvoříme TCP server
    	server = new QTcpServer(this);
    
    	// zajistíme zpracování požadavků vlastním slotem
    	connect(server, SIGNAL(newConnection()), this, SLOT(handleNewConnection()));
    
    	// každou minutu pročistíme záznam přihlašování
    	QTimer::singleShot(60*1000, this, SLOT(purgeLog()));
    
    	// explicitně zakážeme použití proxy
    	server->setProxy(QNetworkProxy::NoProxy);
    	// nastavíme max. počet spojení
    	server->setMaxPendingConnections(50);
    
    	// nastavíme IP a port pro naslouchání
    	bool listening = server->listen(addr, port);
    
    	// uložíme si IP adresu s portem do řetězce ve tvaru IP:port (jen pro výpis)
    	QString ipport = addr.toString() + ":" + QString::number(port);
    
    	// pokud se TCP server nepodařilo spustit na dané IP a portu
    	if(not listening)
    	{
    		// vypíšeme chybovou hlášku
    		cerr << tr("couldn't bind to %1, quitting…").arg(ipport) + "\n";
    		// zajistíme okamžitý zápis na stderr
    		cerr.flush();
    		// tímto zajistíme ukončení programu po provedení konstruktoru
    		QTimer::singleShot(0, qApp, SLOT(quit()));
    	} else
    	{
    		cerr << tr("listening on %1").arg(ipport) + "\n";
    		cerr.flush();
    	}
    }
    
    // (ihned) zapíše data do socketu
    void TcpServer::socketWrite(QTcpSocket* socket, QByteArray data)
    {
    	// zapíše data
    	socket->write(data);
    	// vynutí okamžitý zápis čekajících dat
    	socket->flush();
    }
    
    // vyprázdní záznam o přihlašování
    void TcpServer::purgeLog()
    {
    	log.clear();
    }
    
    // zpracuje nové příchozí spojení
    void TcpServer::handleNewConnection()
    {
    	// získáme socket
    	QTcpSocket* socket = server->nextPendingConnection();
    	if(!socket)
    		return;
    
    	cerr << tr("incoming connection from ") << socket->peerAddress().toString() << "\n";
    	cerr.flush();
    
    	// komunikace s klientem
    	connect(socket, SIGNAL(readyRead()), SLOT(reply()));
    	// šetříme paměť a zajistíme smazání socketu po jeho odpojení
    	connect(socket, SIGNAL(disconnected()), SLOT(gotDisconnected()));
    
    	// požádáme klienta, aby se přihlásil
    	this->socketWrite(socket, "LOGIN");
    }
    
    // vyřizuje odpověď na příchozí požadavky
    void TcpServer::reply()
    {
    	// získáme socket (skrz objekt, který vyslal signál)
    	QTcpSocket* socket = qobject_cast<QTcpSocket*>(this->sender());
    
    	if(log.value(socket->peerAddress().toString(), 0) >= 10)
    		this->socketWrite(socket, "TOOMANYWRONGLOGINS");
    
    	// požadavek
    	QByteArray rawdata = socket->readAll();
    	// argumenty požadavku
    	QList<QByteArray> args = rawdata.split(' ');
    	// samotný příkaz
    	QString command = args.takeFirst();
    	// přihlašovací/uživatelské jméno
    	QString user = logins.value(socket);
    
    	qDebug() << rawdata;
    
    	if(command == "LOGIN" || command == "FORCELOGIN")
    	{ // klient se chce přihlásit
    		// klient je již přihlášen (na tomto socketu)
    		if(!user.isEmpty())
    		{
    			this->socketWrite(socket, "ALREADYLOGGED");
    			return;
    		}
    
    		// vynucené přihlášení?
    		bool force = (command == "FORCELOGIN");
    		// heslo
    		QString pass;
    
    		// špatný počet argumentů nebudeme tolerovat
    		if(args.size() == 2)
    		{
    			user = args.at(0);
    			pass = args.at(1);
    		}
    
    		// zahájíme přihlašování
    		this->login(socket, user, pass, force);
    		return;
    	}
    
    	if(user.isEmpty())
    	{
    		socket->disconnectFromHost();
    
    		QString ip(socket->peerAddress().toString());
    		cerr << tr("a client (IP=%1) has requested something without being logged in,").arg(ip)
    		     << "\n" << tr("which is suspicious – closing the connection.") << "\n";
    		cerr.flush();
    	}
    
    	if(command == "LIST")
    	{ // klient žádá o seznam svých TODO položek
    		this->listItems(socket);
    	} else
    	if(command == "ADD")
    	{ // klient si přeje přidat novou TODO položku
    		this->addItem(socket, rawdata.right( rawdata.size()-command.size()-1 ));
    	} else
    	if(command == "REMOVE")
    	{ // klient si přeje odstranit položky
    		this->removeItems(socket, rawdata.right( rawdata.size()-command.size()-1 )
    						 .split(' '));
    	} else
    	{ // klient poslal neplatný příkaz
    		this->socketWrite(socket, "INVALIDCMD");
    
    		cerr << "invalid command: " << command << "\n";
    		cerr.flush();
    
    		return;
    	}
    }
    
    // přihlásí uživatele
    void TcpServer::login(QTcpSocket* socket, const QString& user,
    		      const QString& pass, bool force)
    {
    	//qDebug() << "user" << user << "is trying to log in with pass" << pass;
    
    	// načteme správné heslo
    	QString realpass = settings.value(QString("logins/%1").arg(user)).toString();
    
    	// a porovnáme jej se zadaným (navíc se ujistíme, zda uživatel vůbec existuje,
    	// abychom ošetřili přihlášení bez hesla)
    	if(!user.isEmpty() && !realpass.isEmpty() && pass == realpass)
    	{ // ok
    		// zjistíme, zda je uživatel již přihlášen odjinud
    		bool alreadyLogged = logins.values().contains(user);
    
    		// pokud ano a nejde o vynucený login…
    		if(alreadyLogged and not force)
    		{
    			// informujeme o tom klienta
    			this->socketWrite(socket, "ALREADYLOGGED");
    			return;
    		}
    
    		// pokud ano a jde o vynucený login…
    		if(alreadyLogged)
    		{
    			// získáme seznam všech socketů
    			QList<QTcpSocket*> keys = logins.keys();
    
    			// a odpojíme ten, který je přihlášený pod daným jménem
    			for(int i=0; i<keys.size(); i++)
    				if(logins.value(keys.at(i)) == user)
    				{
    					QTcpSocket* oldSocket = keys.at(i);
    					oldSocket->disconnectFromHost();
    
    					logins.remove(oldSocket);
    					break;
    				}
    		}
    
    		// pošleme odpověď
    		this->socketWrite(socket, "LOGGED");
    
    		// přiřadíme si socket k uživatelskému jménu do seznamu přihlášení
    		logins.insert(socket, user);
    
    		cerr << tr("user %1 successfully logged in").arg(user) << "\n";
    		cerr.flush();
    
    	} else
    	{ // špatný login
    		this->socketWrite(socket, "WRONGLOGIN");
    
    		// odpojíme klienta
    		socket->disconnectFromHost();
    
    		// zaznamenáme chybný login
    		QString ip(socket->peerAddress().toString());
    		log.insert(ip, log.value(ip, 0)+1);
    
    		cerr << tr("user %1 tried to log in with a wrong password, "
    				   "closing the connection").arg(user) << "\n";
    		cerr.flush();
    	}
    }
    
    // opraví klíče (indexy) položek v nastavení tak, aby šly po sobě (000 až 999)
    void TcpServer::sortKeys(QString user)
    {
    	// získáme seznam klíčů
    	QStringList keys = settings.allKeys();
    
    	// seznam je skutečně plný, nedá se nic dělat
    	if(keys.size() > 999)
    		return;
    
    	cerr << tr("re-sorting %1's todo list").arg(user) + "\n";
    	cerr.flush();
    
    	// získáme seznam položek
    	QStringList items;
    	foreach(QString key, keys)
    		items << settings.value(key).toString();
    
    	//qDebug() << "items:" << items;
    
    	// odstraníme všechny položky
    	settings.remove("");
    
    	// a přidáme je zpátky se správnými klíči
    	for(int key = 0; key < keys.size(); key++)
    		settings.setValue(this->getKey(user, key), items.at(key));
    
    	settings.sync();
    }
    
    // vrátí klíč (index), pod kterým se položka uloží
    QString TcpServer::getKey(QString user, int index)
    {
    	QString key = QString::number(index);
    
    	if(index < 10) // pokud je index menší než 10
    		key.prepend("00"); // přidáme dvě nuly (5 -> 005), atd.
    	else if(index < 100)
    		key.prepend("0");
    	else if(index < 1000)
    		Q_UNUSED(key)
    	else
    	{ // index je vyšší než 999, zkusíme to ještě zachránit
    		// zkusíme opravit indexy
    		this->sortKeys(user);
    
    		// načteme poslední index a přičteme k němu 1
    		int nIndex = settings.allKeys().last().toInt() + 1;
    
    		// pokud je menší než 1000, povedlo se…
    		if(nIndex < 1000)
    			key = this->getKey(user, nIndex);
    		else    // prázdný klíč = plný seznam
    			key.clear();
    	}
    
    	return key;
    }
    
    // odešle klientovi seznam jeho položek
    void TcpServer::listItems(QTcpSocket* socket)
    {
    	// načteme si uživatelské jméno
    	QString user = logins.value(socket);
    
    	// odpověď
    	QByteArray reply;
    
    	settings.beginGroup("todolist_" + user);
    	QStringList keys = settings.allKeys();
    
    	// přidáme do odpovědi seznam všech položek
    	foreach(QString key, keys)
    		reply += settings.value(key).toString() + '\n';
    
    	settings.endGroup();
    
    	// ořízneme poslední \n
    	reply.chop(1);
    
    	// přidáme odpovídající příkaz
    	if(reply.isEmpty())
    		reply = "LISTEMPTY";
    	else
    		reply.prepend("LISTING ");
    
    	//qDebug() << reply;
    
    	// a odpovíme
    	this->socketWrite(socket, reply);
    }
    
    // přidá položku do seznamu uživatele
    void TcpServer::addItem(QTcpSocket* socket, QString item)
    {
    	QString user = logins.value(socket);
    
    	settings.beginGroup("todolist_" + user);
    
    	// zjistíme, pod kterým klíčem/indexem položku uložit
    	int index;
    	if(settings.allKeys().size() > 0)
    		// k poslednímu uloženému indexu přičteme 1
    		index = settings.allKeys().last().toInt() + 1;
    	else    // první index bude 0
    		index = 0;
    
    	//qDebug() << "index:" << index;
    
    	// získáme klíč ve správném formátu
    	QString key = this->getKey(user, index);
    	// prázdný klíč = plný seznam
    	if(key.isEmpty())
    	{
    		// informujeme klienta, že má plný seznam TODO
    		this->socketWrite(socket, "LISTFULL");
    
    		// nezapomeneme ukončit skupinu!
    		settings.endGroup();
    
    		cerr << tr("user %1 has got a full todo list").arg(user) << "\n";
    		cerr.flush();
    		return;
    	}
    
    	// uložíme položku
    	settings.setValue(key, item);
    
    	// sestrojíme odpověď
    	QByteArray reply = "ADDED ";
    	reply += settings.value(key).toString();
    
    	settings.endGroup();
    
    	// odešleme odpověď
    	this->socketWrite(socket, reply);
    
    	// zapíšeme změny v TODO
    	settings.sync();
    }
    
    // odstraní vybrané položky ze seznamu
    void TcpServer::removeItems(QTcpSocket* socket, QList<QByteArray> keys)
    {
    	QString user = logins.value(socket);
    
    	QByteArray reply = "REMOVED";
    
    	settings.beginGroup("todolist_" + user);
    	QStringList savedKeys = settings.allKeys();
    
    	foreach(QByteArray key, keys)
    	{
    		int index = key.toInt();
    		settings.remove(savedKeys.at(index));
    		reply += " " + key;
    	}
    
    	settings.endGroup();
    	settings.sync();
    
    	this->socketWrite(socket, reply);
    }
    
    // klient se odpojil
    void TcpServer::gotDisconnected()
    {
    	// získáme ukazatel na objekt (socket), který vyslal signál
    	QTcpSocket* socket = qobject_cast<QTcpSocket*>( this->sender() );
    
    	// získáme přihlašovací jméno
    	QString user = logins.value(socket);
    
    	if(user.isEmpty())
    		user = "*not logged*";
    	else    // odstraníme ze seznamu aktivních připojení
    		logins.remove(socket);
    
    	// smažeme socket
    	socket->deleteLater();
    
    	cerr << tr("a client (%1) has disconnected").arg(user) << "\n";
    	cerr.flush();
    }
    

    main.cpp:

    #include <QCoreApplication>
    #include <QDebug>
    #include <QHostAddress>
    #include <QStringList>
    #include <QTextCodec>
    
    #include "tcpserver.h"
    
    int main(int argc, char *argv[])
    {
    	QCoreApplication a(argc, argv);
    
    	// výchozí port
    	int port = 2266;
    	// výchozí adresa pro naslouchání
    	QHostAddress addr(QHostAddress::Any);
    	// je vše v pořádku pro spuštění programu?
    	bool ok = true;
    
    	// kontrola argumentů na příkazovém řádku
    	if(argc > 3)
    	{
    		ok = false;
    	} else
    	{
    		if(argc == 3)
    			port = a.arguments().at(2).toInt(&ok);
    
    		if(argc > 1)
    			ok = addr.setAddress(a.arguments().at(1));
    	}
    
    	if(not ok)
    	{
    		qDebug() << "usage:" << argv[0] << "[IP(0.0.0.0)] [port(2266)]";
    		return 1;
    	}
    
    	a.setApplicationName("todoserver");
    	a.setOrganizationDomain("watzke.cz");
    
    	// nastavíme kódování C řetězců
    	QTextCodec::setCodecForCStrings( QTextCodec::codecForName("UTF-8") );
    
    	TcpServer s(addr, port);
    
    	return a.exec();
    }
    

    Zdrojáky si můžete stáhnout v archívu tcpserver.tar.bz2.

           

    Hodnocení: 100 %

            špatnédobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    progdan avatar 16.9.2009 02:39 progdan | skóre: 34 | blog: Archař | Teplice/Brno
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 3 (TCP server)
    Odkaz v uvodu clanku odkazuje asi jinam nez by mel :-) Ale jinak skvely pocteni Davide
    Collecting data is only the first step toward wisdom, but sharing data is the first step toward the community.
    David Watzke avatar 16.9.2009 06:49 David Watzke | skóre: 74 | blog: Blog... | Praha
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 3 (TCP server)
    Odkaz v uvodu clanku odkazuje asi jinam nez by mel :-)
    Jo, díky. To je tím, že ten článek měl původně č. 9, ale nakonec předběhl původní osmičku :-) To pak musí opravit někdo z vyšších adminů.
    Ale jinak skvely pocteni Davide
    To jsem rád, díky.
    “Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
    16.9.2009 09:34 Robert Krátký | skóre: 94 | blog: Robertův bloček
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 3 (TCP server)
    Sorry, opravil jsem článek a zapomněl přizpůsobit odkazy. Už by to mělo být v pořádku.
    16.9.2009 08:22 trekker.dk | skóre: 72
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 3 (TCP server)
    a potom lze použít blokovací metodu waitForNewConnection()
    spíš bych napsal blokující. Blokovací vyznívá tak, že účelem té metody je blokovat.
    Quando omni flunkus moritati
    25.12.2015 10:11 trickyapovery
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 3 (TCP server)
    Možná se najdou i lidi(jako jsem já), kteří článek z abclinuxu "drze" testují na windows a tak by asi neškodilo zmínit, že v takovém případě se ve výchozím nastavení nepoužije konfigurační soubor, ale registr windows. Tzn. je nutné ručně vytvořit podklíč HKCU\Software\watzke.cz\todoserver\logins\ a zde pro každého uživatele řetězcovou hodnotu, kde její název je uživatel a její hodnota je sha1 hesla. (pokud teda zůstane beze změny příkaz a.setApplicationName("todoserver"); a taky a.setOrganizationDomain("watzke.cz"); v main.cpp), jinak se podklíče musí adekvátně změnit. Jinak se mi článek líbí...

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.