Sockets - Server & Client using QT
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 "400 Bad Request 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 (contact@bogotobogo.com).
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
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization