WIP-How to create a simple chat application
Introduction
This article will illustrate a simple chat client and server communicating over TCP. The aim is to clarify aspects of QTcpSocket/QTcpServer that are not developed in the official Qt Fortune example. This has no intention to be a fully featured chat application
The Logic
This application will use a central server that will manage the communication among clients via JSON messages. On the server side, we'll distribute the clients over multiple threads to speed up the processing.
The Server Socket
The fist class we'll look at is the socket on the server that will communicate with a single client
#include <QTcpSocket>
class ServerSocket : public QTcpSocket
{
Q_OBJECT
Q_DISABLE_COPY(ServerSocket)
public:
explicit ServerSocket(QObject* parent = nullptr);
private slots:
void receiveJson();
void sendJson(const QByteArray& jsonData);
signals:
void jsonReceived(const QJsonDocument& jsonDoc);
};
The declaration is very simple, we are just adding 2 slots: sendJson to send messages to the client and receiveJson to receive and decode a message coming from the client. The jsonReceived signal will notify the server of incoming data.
#include "serversocket.h"
#include <QDataStream>
#include <QJsonDocument>
#include <QJsonParseError>
ServerSocket::ServerSocket(QObject* parent)
:QTcpSocket(parent)
{
connect(this,&ServerSocket::readyRead,this,&ServerSocket::receiveJson);
}
void ServerSocket::sendJson(const QByteArray &jsonData)
{
QDataStream socketStream(this);
socketStream.setVersion(QDataStream::Qt_5_9);
socketStream << jsonData;
}
void ServerSocket::receiveJson()
{
QByteArray jsonData;
QDataStream socketStream(this);
socketStream.setVersion(QDataStream::Qt_5_9);
socketStream.startTransaction();
socketStream >> jsonData;
if(socketStream.commitTransaction()){
QJsonParseError parseError;
const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData,&parseError);
if(parseError.error == QJsonParseError::NoError)
emit jsonReceived(jsonDoc);
}
}
The implementation is also relatively straightforward. The constructor calls the base class and the connects the readyRead signal to receiveJson slot that will take care of decoding the data. sendJson