http://www.bogotobogo.com/cplusplus/sockets_server_client_QT.php
Updates: This tutorial was written with Qt4.8. But some of them (e.g. QHttp) have been deprecated in Qt5. We can get updates from Qt5 tutorials:
The code below do download a header file from http://www.bogotobogo.com/
Files including project file are DoHttp.tar.
First, let Qt project (DoHttp.pro) know we're going to use module, network.
QT += core
QT += network
QT -= gui
TARGET = DoHttp
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
downloader.cpp
HEADERS += \
downloader.h
main.cpp should look like this:
#include <QCoreApplication> #include "downloader.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); downloader cDown; cDown.Do_Download(); return a.exec(); }
The downloader class files: downloader.h
// downloader.h #ifndef DOWNLOADER_H #define DOWNLOADER_H #include <QObject> #include <QHttp> #include <QFile> #include <QDebug> class downloader : public QObject { Q_OBJECT public: explicit downloader(QObject *parent = 0); void Do_Download(); signals: public slots: void stateChanged(int state); void responseHeaderReceived ( const QHttpResponseHeader & resp ); void requestFinished ( int id, bool error ); private: QHttp *http; }; #endif // DOWNLOADER_H
downloader.cpp:
#include "downloader.h"
downloader::downloader(QObject *parent) :
QObject(parent)
{
}
void downloader::Do_Download()
{
http = new QHttp(this);
connect(http, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)));
connect(http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)),
this, SLOT(responseHeaderReceived(QHttpResponseHeader)));
connect(http, SIGNAL(requestFinished(int,bool)),
this, SLOT(requestFinished(int,bool)));
http->setHost("bogotobogo.com");
// get default file
http->get("/");
}
void downloader::stateChanged(int state)
{
switch(state)
{
case 0:
qDebug() << "Unconnected";
break;
case 1:
qDebug() << "Host Lookup";
break;
case 2:
qDebug() << "Connecting";
break;
case 3:
qDebug() << "Sending";
break;
case 4:
qDebug() << "Reading";
break;
case 5:
qDebug() << "Connect";
break;
case 6:
qDebug() << "Closing";
break;
}
}
void downloader::responseHeaderReceived ( const QHttpResponseHeader & resp )
{
qDebug() << "Size" << resp.contentLength();
qDebug() << "Type" << resp.contentType();
qDebug() << "Status" << resp.statusCode();
}
void downloader::requestFinished ( int id, bool error )
{
if(error)
{
qDebug() << "ERROR!";
}
else
{
qDebug() << "OK!";
QFile *file = new QFile("/home/KHong/DoHttp/downloaded.txt");
if(file->open(QFile::Append))
{
file->write(http->readAll());
file->flush();
file->close();
}
delete file;
}
}
Here is a table that shows the enum for all states:
enum QHttp::State
Constant | Value | Description |
---|---|---|
QHttp::Unconnected | 0 | There is no connection to the host. |
QHttp::HostLookup | 1 | A host name lookup is in progress. |
QHttp::Connecting | 2 | An attempt to connect to the host is in progress. |
QHttp::Sending | 3 | The client is sending its request to the server. |
QHttp::Reading | 4 | The client's request has been sent and the client is reading the server's response. |
QHttp::Connected | 5 | The connection to the host is open, but the client is neither sending a request, nor waiting for a response. |
QHttp::Closing | 6 | The connection is closing down, but is not yet closed. (The state will be Unconnected when the connection is closed.) |
The output from the run:
OK! Connecting Sending Reading Size 285 Type "text/html" Status 200 Connect OK! Closing Unconnected
The following codes makes a connection to a host using Q3Socket::connectToHost().
Here is the description of connectToHost():
Attempts to make a connection to host on the specified port and return immediately.
Any connection or pending connection is closed immediately, and Q3Socket goes into the HostLookup state. When the lookup succeeds, it emits hostFound(), starts a TCP connection and goes into the Connecting state. Finally, when the connection succeeds, it emits connected() and goes into the Connected state. If there is an error at any point, it emits error().
host may be an IP address in string form, or it may be a DNS name. Q3Socket will do a normal DNS lookup if required. Note that port is in native byte order, unlike some other libraries.
Here is the file used in this section: SocketTest.tar.gz
// main.cpp #include <QCoreApplication> #include "sockettest.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); SocketTest cTest; cTest.Connect(); return a.exec(); }
sockettest.h
#ifndef SOCKETTEST_H #define SOCKETTEST_H #include <QObject> #include <QTcpSocket> #include <QDebug7gt; class SocketTest : public QObject { Q_OBJECT public: explicit SocketTest(QObject *parent = 0); void Connect(); signals: public slots: private: QTcpSocket *socket; }; #endif // SOCKETTEST_H
sockettest.cpp
#include "sockettest.h"
SocketTest::SocketTest(QObject *parent) :
QObject(parent)
{
}
void SocketTest::Connect()
{
socket = new QTcpSocket(this);
socket->connectToHost("bogotobogo.com", 80);
if(socket->waitForConnected(3000))
{
qDebug() << "Connected!";
// send
socket->write("hello server\r\n\r\n\r\n\r\n");
socket->waitForBytesWritten(1000);
socket->waitForReadyRead(3000);
qDebug() << "Reading: " << socket->bytesAvailable();
qDebug() << socket->readAll();
socket->close();
}
else
{
qDebug() << "Not connected!";
}
// sent
// got
// closed
}
Output should look like this:
Connected! Reading: 414 "Bad Request
Your browser sent a request that this server could not understand.
Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
Apache Server at just78.justhost.com Port 80 "
Unfortunately, I got bad request though I got some response from the server. I'll fix this problem later. Any comments on the code will be very much appreciated ([email protected]).
Here is the file used in this section: SignalSocket.tar.gz
In this section, as a continuous series of QTcpSocket, we used the signal/slot mechanism of Qt.
Here is our main() function:
// main.cpp #include <QCoreApplication> #include "sockettest.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); SocketTest mTest; mTest.Test(); return a.exec(); }
Header file:
// sockettest.h
#ifndef SOCKETTEST_H
#define SOCKETTEST_H
#include <QObject>
#include <QDebug>
#include <QTcpSocket>
#include <QAbstractSocket>
class SocketTest : public QObject
{
Q_OBJECT
public:
explicit SocketTest(QObject *parent = 0);
void Test();
signals:
public slots:
void connected();
void disconnected();
void bytesWritten(qint64 bytes);
void readyRead();
private:
QTcpSocket *socket;
};
#endif // SOCKETTEST_H
Then, the implementation file:
// SocketTest.cpp #include "sockettest.h" SocketTest::SocketTest(QObject *parent) : QObject(parent) { } void SocketTest::Test() { socket = new QTcpSocket(this); connect(socket, SIGNAL(connected()), this, SLOT(connected())); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64))); qDebug() << "Connecting,.."; socket->connectToHost("bogotobogo.com", 80); if(!socket->waitForDisconnected(1000)) { qDebug() << "Error: " << socket->errorString(); } } void SocketTest::connected() { qDebug() << "Connected!"; socket->write("HEAD / HTTP/1.0\r\n\r\n\r\n\r\n"); } void SocketTest::disconnected() { qDebug() << "Disconnected!"; } void SocketTest::bytesWritten(qint64 bytes) { qDebug() << "We wrote: " << bytes; } void SocketTest::readyRead() { qDebug() << "Reading..."; qDebug() << socket->readAll(); }
Output looks like this:
Connected! Connected! Connected! Reading... "HTTP/1.1 200 OK Date: Mon, 08 Apr 2013 23:50:29 GMT Server: Apache Accept-Ranges: bytes Vary: Accept-Encoding Connection: close Content-Type: text/html " Disconnected!
In this section, we're doing very basic server/client talks with Qt.
While the server is listening, the client tries to connect to the server. Here are two screen shots from server and client:
As we can see from the picture above, the server has been started and listening.
The client did telnet to loopback (127.0.0.1) with the listening port 1234, and got the response from the server hello client.
Here is the file used in this section: MyFirstServer.tar.gz
main.cpp:
// main.cpp #include <QCoreApplication> #include "myserver.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyServer mServer; return a.exec(); }
Header file, myserver.h:
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QObject>
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
class MyServer : public QObject
{
Q_OBJECT
public:
explicit MyServer(QObject *parent = 0);
signals:
public slots:
void newConnection();
private:
QTcpServer *server;
};
#endif // MYSERVER_H
Implementation file, myserver.cpp:
// myserver.cpp #include "myserver.h" MyServer::MyServer(QObject *parent) : QObject(parent) { server = new QTcpServer(this); connect(server, SIGNAL(newConnection()), this, SLOT(newConnection())); if(!server->listen(QHostAddress::Any, 1234)) { qDebug() << "Server could not start!"; } else { qDebug() << "Server started!"; } } void MyServer::newConnection() { QTcpSocket *socket = server->nextPendingConnection(); socket->write("hello client\r\n"); socket->flush(); socket->waitForBytesWritten(3000); socket->close(); }
The resulting screen shots of the code are in the picture below.
The picture at the top is a server screen shot. It was listening and then got connected from the two clients whose IDs are 7 and 9, respectively. Server printed out the message it got from those clients. The two pictures below the server screen shot are from two clients, ID(7) and ID(9). They echoed their messages to servers.
Note that whenever there is a new connection, a new thread will be created.
Here is the file used in this section: MultiServer.tar.gz
main.cpp
#include <QCoreApplication> #include "myserver.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyServer Server; Server.StartServer(); return a.exec(); }
hearder file, myserver.h
// myserver.h #ifndef MYSERVER_H #define MYSERVER_H #include <QTcpServer> #include <QDebug> #include "mythread.h" class MyServer : public QTcpServer { Q_OBJECT public: explicit MyServer(QObject *parent = 0); void StartServer(); signals: public slots: protected: void incomingConnection(int socketDescriptor); }; #endif // MYSERVER_H
Implementation file, myserver.cpp
// myserver.cpp
#include "myserver.h"
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
}
void MyServer::StartServer()
{
if(!this->listen(QHostAddress::Any,1234))
{
qDebug() << "Could not start server";
}
else
{
qDebug() << "Listening...";
}
}
void MyServer::incomingConnection(int socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting...";
MyThread *thread = new MyThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
Another header, mythread.h
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> #include <QTcpSocket> #include <QDebug> class MyThread : public QThread { Q_OBJECT public: explicit MyThread(int iID, QObject *parent = 0); void run(); signals: void error(QTcpSocket::SocketError socketerror); public slots: void readyRead(); void disconnected(); public slots: private: QTcpSocket *socket; int socketDescriptor; }; #endif // MYTHREAD_H
Finally, another implementation file, mythread.cpp
// mythread.cpp #include "mythread.h" MyThread::MyThread(int ID, QObject *parent) : QThread(parent) { this->socketDescriptor = ID; } void MyThread::run() { // thread starts here qDebug() << socketDescriptor << " Starting thread"; socket = new QTcpSocket(); if(!socket->setSocketDescriptor(this->socketDescriptor)) { emit error(socket->error()); return; } connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()),Qt::DirectConnection); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()),Qt::DirectConnection); qDebug() << socketDescriptor << " Client connected"; // make this thread a loop exec(); } void MyThread::readyRead() { QByteArray Data = socket->readAll(); qDebug() << socketDescriptor << " Data in: " << Data; socket->write(Data); } void MyThread::disconnected() { qDebug() << socketDescriptor << " Disconnected"; socket->deleteLater(); exit(0); }
The resulting screen shots of the code are in the picture below.
The picture at the top is a server screen shot. It was listening and then got connected from the client.
Note that whenever there is a new connection, a new thread will be created from the ThreadPool and takes a task from the QRunnable object.
Here is the file used in this section: PoolSvr.tar.gz
Our codes are:
main.cpp
#include <QCoreApplication> #include "myserver.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyServer Server; Server.StartServer(); return a.exec(); }
MyServer header, myserver.h
#ifndef MYSERVER_H #define MYSERVER_H #include <QTcpServer> #include <QThreadPool> #include <QDebug> #include "myrunnable.h" class MyServer : public QTcpServer { Q_OBJECT public: explicit MyServer(QObject *parent = 0); void StartServer(); protected: void incomingConnection( int handle ); signals: public slots: private: QThreadPool *pool; }; #endif // MYSERVER_H
Implementation file MyServer.cpp
// MyServer.cpp #include "myserver.h" MyServer::MyServer(QObject *parent) : QTcpServer(parent) { pool = new QThreadPool(this); pool->setMaxThreadCount(5); } void MyServer::StartServer() { if(this->listen(QHostAddress::Any, 1234)) { qDebug() << "Server started"; } else { qDebug() << "Server did not start!"; } } void MyServer::incomingConnection(int handle) { MyRunnable *task = new MyRunnable(); task->setAutoDelete(true); task->SocketDescriptor = handle; pool->start(task); }
Runnable header, myrunnable.h
// myrunnable.h #ifndef MYRUNNABLE_H #define MYRUNNABLE_H #include <QRunnable> #include <QTcpSocket> #include <QDebug> class MyRunnable : public QRunnable { public: MyRunnable(); int SocketDescriptor; protected: void run(); }; #endif // MYRUNNABLE_H
The implementation file, MyRunnalbe.cpp
// MyRunnalbe.cpp #include "myrunnable.h" MyRunnable::MyRunnable() { } void MyRunnable::run() { if(!SocketDescriptor) return; QTcpSocket socket; socket.setSocketDescriptor(SocketDescriptor); socket.write("hello world"); socket.flush(); socket.waitForBytesWritten(); socket.close(); }
The resulting screen shots of the code are in the pictures below.
Server screen shot
Client at 7 screen shot
Client at 8 screen shot
The picture at the top is a server screen shot. It was listening and then got connected from the client.
Note that whenever there is a new connection, a new thread will be created from the ThreadPool and takes a task from the QRunnable object.
The other two pictures are the shots from the client at 7 and 8. At each return key on client window, a new thread created and run the task on the thread which is managed by Qt.
Here is the file used in this section: AsSvr2.tar.gz
main.cpp
#include <QCoreApplication> #include "myserver.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // Create an instance of a server and then start it. MyServer Server; Server.StartServer(); return a.exec(); }
Header myserver.h
// myserver.h #ifndef MYSERVER_H #define MYSERVER_H #include <QTcpServer> #include <QTcpSocket> #include <QAbstractSocket> #include "myclient.h" class MyServer : public QTcpServer { Q_OBJECT public: explicit MyServer(QObject *parent = 0); void StartServer(); protected: void incomingConnection(int handle); signals: public slots: }; #endif // MYSERVER_H
Implementation file, myserver.cpp
// myserver.cpp
#include "myserver.h"
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
}
void MyServer::StartServer()
{
if(listen(QHostAddress::Any, 1234))
{
qDebug() << "Server: started";
}
else
{
qDebug() << "Server: not started!";
}
}
void MyServer::incomingConnection(int handle)
{
// at the incoming connection, make a client
MyClient *client = new MyClient(this);
client->SetSocket(handle);
}
Client header, myclient.h
// myclient.h #ifndef MYCLIENT_H #define MYCLIENT_H #include <QObject> #include <QTcpSocket> #include <QDebug> #include <QThreadPool> #include "mytask.h" class MyClient : public QObject { Q_OBJECT public: explicit MyClient(QObject *parent = 0); void SetSocket(int Descriptor); signals: public slots: void connected(); void disconnected(); void readyRead(); // make the server fully ascynchronous // by doing time consuming task void TaskResult(int Number); private: QTcpSocket *socket; }; #endif // MYCLIENT_H
Client implementation file, myclient.cpp
//myclient.cpp #include "myclient.h" MyClient::MyClient(QObject *parent) : QObject(parent) { QThreadPool::globalInstance()->setMaxThreadCount(5); } void MyClient::SetSocket(int Descriptor) { // make a new socket socket = new QTcpSocket(this); qDebug() << "A new socket created!"; connect(socket, SIGNAL(connected()), this, SLOT(connected())); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); socket->setSocketDescriptor(Descriptor); qDebug() << " Client connected at " << Descriptor; } // asynchronous - runs separately from the thread we created void MyClient::connected() { qDebug() << "Client connected event"; } // asynchronous void MyClient::disconnected() { qDebug() << "Client disconnected"; } // Our main thread of execution // This happening via main thread // Our code running in our thread not in Qthread // That's why we're getting the thread from the pool void MyClient::readyRead() { qDebug() << "MyClient::readyRead()"; qDebug() << socket->readAll(); // Time consumer MyTask *mytask = new MyTask(); mytask->setAutoDelete(true); connect(mytask, SIGNAL(Result(int)), this, SLOT(TaskResult(int)), Qt::QueuedConnection;) qDebug() << "Starting a new task using a thread from the QThreadPool"; QThreadPool::globalInstance()->start(mytask); } // After a task performed a time consuming task. // We grab the result here, and send it to client void MyClient::TaskResult(int Number) { QByteArray Buffer; Buffer.append("\r\nTask result = "); Buffer.append(QString::number(Number)); socket->write(Buffer); }
Task header, mytask.h
//mytask.h
#ifndef MYTASK_H
#define MYTASK_H
#include <QRunnable>
#include <QObject>
#include <QRunnable>
// Q_OBJECT missing in the original file generated by class wizard.
// because we set this class with base class QRunnable
// with no inheritance in the class wizard
// We do not have this. So, we cannot use signal/slot
// But we need them.
// Thus, we should use multiple inheritance: QObject inserted here
class MyTask : public QObject, public QRunnable
{
Q_OBJECT
public:
MyTask();
signals:
// notify to the main thread when we're done
void Result(int Number);
protected:
void run();
};
#endif // MYTASK_H
Implementation of task, mytask.cpp
#include "mytask.h" #include <QDebug> MyTask::MyTask() { qDebug() << "MyTask()"; } // When the thread pool kicks up, and implements Qrunnable // it's going to hit this run, and it's going to do this time consuming task. // After it's done, we're going to send the results back to our main thread. // This runs in the separate thread, and we do not have any control over this thread, // but Qt does. // This may just stay in the queue for several ms depending on how busy the server is. void MyTask::run() { // time consumer qDebug() << "Task start"; int iNumber = 0; for(int i = 0; i < 100; i++) { iNumber += 1; } qDebug() << "Task done"; emit Result(iNumber); }
When we have "QApplication: no such file or directory" error, we now have to add widgets to the QT qmake variable in .pro:
QT += widgets
For other Qt tutorials, please visit