QTcpServer and QTcpSocket

The TCP defines two roles for communication – the server that waits for a client to initiate the connection, and the client that will then send and receive data. The following code example shows the basic usage of a QTcpServer class:

server = new QTcpServer(this);
server ->listen(QHostAddress::any, 8044);
connect(server, &QTcpServer::newConnection,
this, &MyClass::acceptClntConn);

We are starting a server and listening on the local port 8044, willing to accept incoming IP v.4 and v.6 connections. The second thing we notice is that QTcpSocket works asynchronously and emits signals to report status changes. Internally, the QTcpSocket will use asynchronous native operating system interfaces such as the MsgWaitForMultipleObjectsEx() system call on Windows and ppoll() on Linux, to wait for events on the underlying socket file description. Due to this, we have to connect to QTcpSocket signals and react to them asynchronously in callbacks. 

Some example callbacks for handling new incoming connections and receiving client data are as follows:

void MyClass::acceptClientConn()
{
QTcpSocket* conn = server->nextPendingConnection();
connect(conn , &QTcpSocket::readyRead, this, MyClass::readClientData);
}

void MyClass::readClientData()
{
QTcpSocket* conn = dynamic_cast<QTcpSocket *>(sender());

if (!conn->canReadLine())
return;

char buf[1024];
conn->readLine(buf, sizeof(buf));
... // process data
}

Here, we used the convenience method readLine(), but we could also use the read() or readAll() methods. We are reading the data from the internal QTcpSocket read buffer, so if we don't read all the data at once, it will still be available later. The incoming data will be appended to that internal buffer, whose size can be changed by calling setReadBufferSize(). By default, the size is 0, meaning unlimited data buffering.

On the client side, we first have to connect to the server port and also to the signals that QTcpSocket emits, as is the case with QTcpServer. Take a look at the following code:

QTcpSocket* client = new QTcpSocket(this);

QHostAddress remoteAddr(...);
client.connectToHost(remoteAddr, 8044);

connect(client, &QTcpSocket::connected, this, &MyClass::connectionOpened);
connect(client, &QTcpSocket::readyRead, this, &MyClass::readServerResponse);

// sending data:
QByteArray data("Hello from client!");
client->write(bytes);

In this book's resources (https://github.com/PacktPublishing/Hands-On-High-performance-with-QT/tree/master/Chapter%209), there is an example program that implements bidirectional client-server communication over TCP.