Qt and TCP

I’ve had a request for examples using TCP with the Qt framework, something it does very well.

QNetworkAccessManager

The simplest way of doing this is simply to connect to a remote resource, such as a webpage, make a request, receive the content and disconnect. The correct way to do this with Qt is to use the QNetworkAccessManager class which is specifically designed to make HTTP requests and abstract away the details of sockets and headers etc. The following full example connects to http://www.google.com/ and receives the HTML code used to construct the Google homepage.

QT       += core gui network

TARGET = QNAM
TEMPLATE = app

SOURCES += main.cpp\
        widget.cpp

HEADERS  += widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui/QWidget>

class QLineEdit;
class QPushButton;
class QTextEdit;
class QNetworkAccessManager;
class QNetworkReply;

class Widget : public QWidget
{
    Q_OBJECT
    
public:
    Widget(QWidget *parent = 0);
    ~Widget();

private:
    QLineEdit *url;
    QPushButton *button;
    QTextEdit *content;
    QNetworkAccessManager *nam;

public slots:
    void makeRequest();
    void processReply(QNetworkReply *reply);
};

#endif // WIDGET_H
#include "widget.h"

#include <QtGui>
#include <QtNetwork>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("QNetworkAccessManager Example");

    nam=new QNetworkAccessManager(this);
    connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(processReply(QNetworkReply*)));

    QVBoxLayout *layout=new QVBoxLayout(this);

    url=new QLineEdit("http://www.google.com/", this);
    layout->addWidget(url);

    button=new QPushButton("Make Request", this);
    connect(button, SIGNAL(clicked()), this, SLOT(makeRequest()));
    layout->addWidget(button);

    content=new QTextEdit(this);
    content->setReadOnly(true);
    layout->addWidget(content);
}

Widget::~Widget(){}

void Widget::makeRequest(){
    QNetworkRequest request(QUrl(url->text()));
    nam->get(request);

    url->setDisabled(true);
    button->setDisabled(true);
}

void Widget::processReply(QNetworkReply *reply){
    if(reply->error()==QNetworkReply::NoError){
        content->setPlainText(reply->readAll());
        url->setDisabled(false);
        button->setDisabled(false);
    }
    else content->setPlainText(QString("Error: %1").arg(reply->errorString()));
}
#include <QtGui/QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    
    return a.exec();
}

Client/Server Example

If you wish to establish/host both ends of the connection and/or transfer data using a custom format or protocol then the following example(s) may be more useful. I’m not going to explain the in’s and out’s of network design, technologies and topologies here (unless requested) but basically the architecture consists of multiple clients creating a unique connection to a single server application via a socket pair.

The following code comprises two applications, one a client and the other a server. The code should be relatively self explanatory, if it isn’t or you require more information/detail then drop a comment at the bottom of the page and I’ll get back to you when I can.

QT       += core gui network

TARGET = TCPClient
TEMPLATE = app

SOURCES += main.cpp\
        tcpclient.cpp

HEADERS  += tcpclient.h
#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QtGui/QWidget>

class QTcpSocket;
class QLineEdit;
class QSpinBox;
class QPushButton;
class QTextEdit;

class TCPClient : public QWidget
{
    Q_OBJECT
    
public:
    TCPClient(QWidget *parent = 0);

private:
    QTcpSocket *socket;
    QLineEdit *host;
    QSpinBox *port;
    QPushButton *control;
    QTextEdit *trace;

public slots:
    void connectToHost();
    void connected();
    void readServer();
};

#endif // TCPCLIENT_H
#include <QtGui>
#include <QtNetwork>

TCPClient::TCPClient(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("TCP Client");

    socket=new QTcpSocket(this);
    connect(socket, SIGNAL(connected()), this, SLOT(connected()));
    connect(socket, SIGNAL(readyRead()), this, SLOT(readServer()));

    QFormLayout *layout=new QFormLayout(this);

    host=new QLineEdit("127.0.0.1", this);
    layout->addRow("Host:", host);

    port=new QSpinBox(this);
    port->setRange(0,9999);
    port->setValue(5000);
    layout->addRow("Port:", port);

    control=new QPushButton("Connect", this);
    connect(control, SIGNAL(clicked()), this, SLOT(connectToHost()));
    layout->addWidget(control);

    trace=new QTextEdit(this);
    trace->setReadOnly(true);
    layout->addWidget(trace);
}

void TCPClient::connectToHost(){
    socket->connectToHost(QHostAddress(host->text()), port->value());
}

void TCPClient::connected(){
    socket->write(QString("Hello Server").toAscii());
    trace->append("Connected");
    socket->waitForBytesWritten();
}

void TCPClient::readServer(){
    trace->append(socket->readAll());
}
#include <QtGui/QApplication>
#include "tcpclient.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TCPClient c;
    c.show();
    
    return a.exec();
}
QT       += core gui network

TARGET = TCPServer
TEMPLATE = app

SOURCES += main.cpp \
    tcpserver.cpp

HEADERS  += \
    tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H

#include <QWidget>

class QTcpServer;
class QTcpSocket;
class QLineEdit;
class QSpinBox;
class QPushButton;
class QTextEdit;

class TCPServer : public QWidget
{
    Q_OBJECT
public:
    explicit TCPServer(QWidget *parent = 0);
    
private:
    QTcpServer *server;
    QList<QTcpSocket*> sockets;
    QLineEdit *host;
    QSpinBox *port;
    QPushButton *control;
    QTextEdit *trace;

public slots:
    void start();
    void processNewConnection();
    void readClient();
};

#endif // TCPSERVER_H
#include "tcpserver.h"

#include <QtGui>
#include <QtNetwork>

TCPServer::TCPServer(QWidget *parent) :
    QWidget(parent)
{
    setWindowTitle("TCP Server");

    server=new QTcpServer(this);
    connect(server, SIGNAL(newConnection()), this, SLOT(processNewConnection()));

    QFormLayout *layout=new QFormLayout(this);

    host=new QLineEdit("127.0.0.1", this);
    layout->addRow("Host:", host);

    port=new QSpinBox(this);
    port->setRange(0,9999);
    port->setValue(5000);
    layout->addRow("Port:", port);

    control=new QPushButton("Start", this);
    connect(control, SIGNAL(clicked()), this, SLOT(start()));
    layout->addWidget(control);

    trace=new QTextEdit(this);
    trace->setReadOnly(true);
    layout->addWidget(trace);
}

void TCPServer::start(){
    if(server->isListening()) return;

    if(!server->listen(QHostAddress(host->text()), port->value()))
        trace->append("Failed to listen!");
    else trace->append("Listening!");
}

void TCPServer::processNewConnection(){
    while(server->hasPendingConnections()){
        trace->append("Accepting connection!");
        QTcpSocket *socket=server->nextPendingConnection();
        connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()));
        sockets.append(socket);
    }
}

void TCPServer::readClient(){
    QTcpSocket *socket=dynamic_cast<QTcpSocket*>(sender());
    trace->append(socket->readAll());
    socket->write(QString("Hello Client").toAscii());
}
#include <QtGui/QApplication>
#include "tcpserver.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TCPServer s;
    s.show();
    
    return a.exec();
}

Edit (27/06/14)
I have had a request to upload the source code for these examples as copying & pasting them is causing some issues (HTML escape characters I’m guessing) so here you go:

5 thoughts on “Qt and TCP

  1. Superb tutorial. Can plz upload the whole program as a zip. Beacuse while doing copy paste of your code many errors were occured.

    • Hi Vishnu,
      Thanks very much for your comment. I’m sorry you had issues working the example code, as you suggested I have added links to zip archives for these projects at the end of the page, I hope this helps ;o)
      Rob

      • Hey! Thanks for the upload. I am using Qt 5.2.1 . QtGui/QApplication no such file or directory. I googled for the solution i added QT += widgets to pro and replaced Qgui/QApplication with . then i got 43 error all the layouts and all are showing errors .Can you plz solve this problem and check it with Qt5.2.1. Finally your explanation is awesome and so clear. Also i request for in’s and out’s of network design, technologies and topologies.Thanks

        • Problem solved. But new question is you have done the connection part . Can you extend it to exchange data between server and client ?

Leave a Reply

Your email address will not be published. Required fields are marked *