abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    včera 15:22 | IT novinky

    Eric Lengyel dobrovolně uvolnil jako volné dílo svůj patentovaný algoritmus Slug. Algoritmus vykresluje text a vektorovou grafiku na GPU přímo z dat Bézierových křivek, aniž by využíval texturové mapy obsahující jakékoli předem vypočítané nebo uložené obrázky a počítá přesné pokrytí pro ostré a škálovatelné zobrazení písma, referenční ukázka implementace v HLSL shaderech je na GitHubu. Slug je volným dílem od 17. března letošního

    … více »
    NUKE GAZA! 🎆 | Komentářů: 0
    včera 15:11 | Zajímavý projekt

    Sashiko (GitHub) je open source automatizovaný systém pro revizi kódu linuxového jádra. Monitoruje veřejné mailing listy a hodnotí navrhované změny pomocí umělé inteligence. Výpočetní zdroje a LLM tokeny poskytuje Google.

    Ladislav Hagara | Komentářů: 3
    včera 04:44 | Zajímavý software

    Cambalache, tj. RAD (rapid application development) nástroj pro GTK 4 a GTK 3, dospěl po pěti letech vývoje do verze 1.0. Instalovat jej lze i z Flathubu.

    Ladislav Hagara | Komentářů: 0
    20.3. 14:55 | Nová verze

    KiCad (Wikipedie), sada svobodných softwarových nástrojů pro počítačový návrh elektronických zařízení (EDA), byl vydán v nové major verzi 10.0.0 (𝕏). Přehled novinek v příspěvku na blogu.

    Ladislav Hagara | Komentářů: 0
    20.3. 13:22 | IT novinky

    Letošní Turingovou cenu (2025 ACM A.M. Turing Award, Nobelova cena informatiky) získali Charles H. Bennett a Gilles Brassard za základní přínosy do oboru kvantové informatiky, které převrátily pojetí bezpečné neprolomitelné komunikace a výpočetní techniky. Jejich protokol BB84 z roku 1984 umožnil fyzikálně zaručený bezpečný přenos šifrovacích klíčů, zatímco jejich práce o kvantové teleportaci položila teoretické základy pro budoucí kvantový internet. Jejich práce spojila fyziku s informatikou a ovlivnila celou generaci vědců.

    Ladislav Hagara | Komentářů: 7
    20.3. 04:44 | Zajímavý článek

    Firefox 149 dostupný od 24. března přinese bezplatnou vestavěnou VPN s 50 GB přenesených dat měsíčně (s CZ a SK se zatím nepočítá) a zobrazení dvou webových stránek vedle sebe v jednom panelu (split view). Firefox Labs 149 umožní přidat poznámky k panelům (tab notes, videoukázka).

    Ladislav Hagara | Komentářů: 2
    20.3. 00:33 | Nová verze

    Byla vydána nová stabilní verze 7.9 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 146. Přehled novinek i s náhledy v příspěvku na blogu.

    Ladislav Hagara | Komentářů: 0
    20.3. 00:11 | Zajímavý software

    Dle plánu byla vydána Opera GX pro Linux. Ke stažení je .deb i .rpm. V plánu je flatpak. Opera GX je webový prohlížeč zaměřený na hráče počítačových her.

    Ladislav Hagara | Komentářů: 7
    19.3. 19:22 | Nová verze

    GNUnet (Wikipedie) byl vydán v nové major verzi 0.27.0. Jedná se o framework pro decentralizované peer-to-peer síťování, na kterém je postavena řada aplikací.

    Ladislav Hagara | Komentářů: 0
    19.3. 04:00 | Bezpečnostní upozornění

    Byly publikovány informace (technické detaily) o bezpečnostním problému Snapu. Jedná se o CVE-2026-3888. Neprivilegovaný lokální uživatel může s využitím snap-confine a systemd-tmpfiles získat práva roota.

    Ladislav Hagara | Komentářů: 4
    Které desktopové prostředí na Linuxu používáte?
     (15%)
     (7%)
     (1%)
     (12%)
     (29%)
     (2%)
     (5%)
     (1%)
     (13%)
     (24%)
    Celkem 1125 hlasů
     Komentářů: 27, poslední 17.3. 19:26
    Rozcestník

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

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

    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.