|  | Home · Overviews · Examples

# The Network Module in Qt 4

The network module in Qt 4 provides some new features, such as support for internationalized domain names, better IPv6 support, and better performance. And since Qt 4 allows us to break binary compatibility with previous releases, we took this opportunity to improve the class names and API to make them more intuitive to use.

- General Overview
- Example Code

- TCP Client
- TCP Server
- UDP Senders and Receivers

- Comparison with Qt 3

## General Overview

Compared to Qt 3, the network module in Qt 4 brings the following benefits:

- The Qt 4 network classes have more intuitive names and APIs. For example, `QServerSocket` has been renamed `QTcpServer`.
- The entire network module is reentrant, making it possible to use them simultaneously from multiple threads.
- It is now possible to send and receive UDP datagrams and to use synchronous (i.e., blocking) sockets without having to use a low-level API (`QSocketDevice` in Qt 3).
- `QHostAddress` and `QHostInfo` support internationalized domain names (RFC 3492).
- `QUrl` is more lightweight and fully supports the latest URI specification draft.
- UDP broadcasting is now supported.

The Qt 4 network module provides fundamental classes for writing TCP and UDP applications, as well as higher-level classes that implement the client side of the HTTP and FTP protocols.

Here's an overview of the TCP and UDP classes:

- `QTcpSocket` encapsulates a TCP socket. It inherits from `QIODevice`, so you can use `QTextStream` and `QDataStream` to read or write data. It is useful for writing both clients and servers.
- `QTcpServer` allows you to listen on a certain port on a server. It emits a newConnection() signal every time a client tries to connect to the server. Once the connection is established, you can talk to the client using `QTcpSocket`.
- `QUdpSocket` is an API for sending and receiving UDP datagrams.

`QTcpSocket` and `QUdpSocket` inherit most of their functionality from `QAbstractSocket`. You can also use `QAbstractSocket` directly as a wrapper around a native socket descriptor.

By default, the socket classes work asynchronously (i.e., they are non-blocking), emitting signals to notify when data has arrived or when the peer has closed the connection. In multithreaded applications and in non-GUI applications, you also have the opportunity of using blocking (synchronous) functions on the socket, which often results in a more straightforward style of programming, with the networking logic concentrated in one or two functions instead of spread across multiple slots.

`QFtp` and `QHttp` use `QTcpSocket` internally to implement the FTP and HTTP protocols. Both classes work asynchronously and can schedule (i.e., queue) requests.

The network module contains four helper classes: `QHostAddress`, `QHostInfo`, `QUrl`, and `QUrlInfo`. `QHostAddress` stores an IPv4 or IPv6 address, `QHostInfo` resolves host names into addresses, `QUrl` stores a URL, and `QUrlInfo` stores information about a resource pointed to by a URL, such as the file size and modification date. (Because `QUrl` is used by `QTextBrowser`, it is part of the QtCore library and not of QtNetwork.)

See the `QtNetwork` module overview for more information.

## Example Code

All the code snippets presented here are quoted from self-contained, compilable examples located in Qt's `examples/network` directory.

### TCP Client

The first example illustrates how to write a TCP client using `QTcpSocket`. The client talks to a fortune server that provides fortune to the user. Here's how to set up the socket:

            tcpSocket = new QTcpSocket(this);

            connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()));
            connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                    this, SLOT(displayError(QAbstractSocket::SocketError)));

When the user requests a new fortune, the client establishes a connection to the server:

            tcpSocket->connectToHost(hostLineEdit->text(),
                                     portLineEdit->text().toInt());

When the server answers, the following code is executed to read the data from the socket:

            QDataStream in(tcpSocket);
            in.setVersion(QDataStream::Qt_4_0);

            if (blockSize == 0) {
                if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
                    return;

                in >> blockSize;
            }

            if (tcpSocket->bytesAvailable() < blockSize)
                return;

            QString nextFortune;
            in >> nextFortune;

            if (nextFortune == currentFortune) {
                QTimer::singleShot(0, this, SLOT(requestNewFortune()));
                return;
            }

            currentFortune = nextFortune;

The server's answer starts with a size field (which we store in `blockSize`), followed by size bytes of data. If the client hasn't received all the data yet, it waits for the server to send more.

An alternative approach is to use a blocking socket. The code can then be concentrated in one function:

                const int Timeout = 5 * 1000;

                QTcpSocket socket;
                socket.connectToHost(serverName, serverPort);

                if (!socket.waitForConnected(Timeout)) {
                    emit error(socket.error(), socket.errorString());
                    return;
                }

                while (socket.bytesAvailable() < (int)sizeof(quint16)) {
                    if (!socket.waitForReadyRead(Timeout)) {
                        emit error(socket.error(), socket.errorString());
                        return;
                    }
                }

                quint16 blockSize;
                QDataStream in(&socket);
                in.setVersion(QDataStream::Qt_4_0);
                in >> blockSize;

                while (socket.bytesAvailable() < blockSize) {
                    if (!socket.waitForReadyRead(Timeout)) {
                        emit error(socket.error(), socket.errorString());
                        return;
                    }
                }

                QMutexLocker locker(&mutex);

                QString fortune;
                in >> fortune;
                emit newFortune(fortune);

### TCP Server

The following code snippets illustrate how to write a TCP server using `QTcpServer` and `QTcpSocket`. Here's how to set up a TCP server:

            tcpServer = new QTcpServer(this);
            if (!tcpServer->listen()) {
                QMessageBox::critical(this, tr("Fortune Server"),
                                      tr("Unable to start the server: %1.")
                                      .arg(tcpServer->errorString()));
                close();
                return;
            }

            connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));

When a client tries to connect to the server, the following code in the sendFortune() slot is executed:

            QByteArray block;
            QDataStream out(&block, QIODevice::WriteOnly);
            out.setVersion(QDataStream::Qt_4_0);
            out << (quint16)0;
            out << fortunes.at(qrand() % fortunes.size());
            out.device()->seek(0);
            out << (quint16)(block.size() - sizeof(quint16));

            QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
            connect(clientConnection, SIGNAL(disconnected()),
                    clientConnection, SLOT(deleteLater()));

            clientConnection->write(block);
            clientConnection->disconnectFromHost();

### UDP Senders and Receivers

Here's how to broadcast a UDP datagram:

            udpSocket = new QUdpSocket(this);
            QByteArray datagram = "Broadcast message " + QByteArray::number(messageNo);
            udpSocket->writeDatagram(datagram.data(), datagram.size(),
                                     QHostAddress::Broadcast, 45454);

Here's how to receive a UDP datagram:

            udpSocket = new QUdpSocket(this);
            udpSocket->bind(45454);

            connect(udpSocket, SIGNAL(readyRead()),
                    this, SLOT(processPendingDatagrams()));

Then in the processPendingDatagrams() slot:

            while (udpSocket->hasPendingDatagrams()) {
                QByteArray datagram;
                datagram.resize(udpSocket->pendingDatagramSize());
                udpSocket->readDatagram(datagram.data(), datagram.size());
                statusLabel->setText(tr("Received datagram: \"%1\"")
                                     .arg(datagram.data()));
            }

## Comparison with Qt 3

The main difference between Qt 3 and Qt 4 is that the very high level `QNetworkProtocol` and `QUrlOperator` abstraction has been eliminated. These classes attempted the impossible (unify FTP and HTTP under one roof), and unsurprisingly failed at that. Qt 4 still provides `QFtp` and `QHttp` classes, but only with the more mature API that appeared in Qt 3.1.

The `QSocket` class in Qt 3 has been renamed `QTcpSocket`. The new class is reentrant and supports blocking. It's also easier to handle closing than with Qt 3, where you had to connect to both the QSocket::connectionClosed() and the QSocket::delayedCloseFinished() signals.

The `QServerSocket` class in Qt 3 has been renamed `QTcpServer`. The API has changed quite a bit. While in Qt 3 it was necessary to subclass `QServerSocket` and reimplement the newConnection() pure virtual function, `QTcpServer` now emits a newConnection() signal that you can connect to a slot.

The `QHostInfo` class has been redesigned to use the operating system's getaddrinfo() function instead of implementing the DNS protocol. Internally, `QHostInfo` simply starts a thread and calls getaddrinfo() in that thread. This wasn't possible in Qt 3 because getaddrinfo() is a blocking call and Qt 3 could be configured without multithreading support.

The `QSocketDevice` class in Qt 3 is no longer part of the public Qt API. If you used `QSocketDevice` to send or receive UDP datagrams, use `QUdpSocket` instead. If you used `QSocketDevice` because it supported blocking sockets, use `QTcpSocket` or `QUdpSocket` instead and use the blocking functions (waitForConnected(), waitForReadyRead(), etc.). If you used `QSocketDevice` from a non-GUI thread because it was the only reentrant networking class in Qt 3, use `QTcpSocket`, `QTcpServer`, or `QUdpSocket` instead.

Internally, Qt 4 has a class called QSocketLayer that provides a cross-platform low-level socket API. It resembles the old `QSocketDevice` class. We might make it public in a later release if users ask for it.

As an aid to porting to Qt 4, the `Qt3Support` library includes Q3Dns, Q3ServerSocket, Q3Socket, and Q3SocketDevice classes.