WIP-How to create a simple chat application: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
(Removed outdated part)
Line 5: Line 5:
=== The Logic ===
=== The Logic ===
This application will use a central server that will manage the communication among clients via [https://www.json.org/ JSON] messages.
This application will use a central server that will manage the communication among clients via [https://www.json.org/ JSON] messages.
On the server side, we'll distribute the clients over multiple threads to speed up the processing.
We'll implement 2 versions of the server, one that runs in a single server and one that distributes the sockets among multiple threads.
=== The Server Socket ===
The fist class we'll look at is the socket on the server that will communicate with a single client
<code>
#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);
};
</code>
The declaration is very simple, we are just adding 2 slots: <tt>sendJson</tt> to send messages to the client and <tt>receiveJson</tt> to receive and decode a message coming from the client.
The <tt>jsonReceived</tt> signal will notify the server of incoming data.
<code>
#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_6);
    socketStream << jsonData;
}
 
void ServerSocket::receiveJson()
{
    QByteArray jsonData;
    QDataStream socketStream(this);
    socketStream.setVersion(QDataStream::Qt_5_6);
    for(;;){
        socketStream.startTransaction();
        socketStream >> jsonData;
        if(socketStream.commitTransaction()){
            QJsonParseError parseError;
            const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData,&parseError);
            if(parseError.error == QJsonParseError::NoError)
                emit jsonReceived(jsonDoc);
        }
        else{
            break;
        }
    }
}
</code>
The implementation is also relatively straightforward.
The constructor calls the base class and the connects the <tt>readyRead</tt> signal to <tt>receiveJson</tt> slot that will take care of decoding the data.
<tt>sendJson</tt> will just write the data to the socket. <tt>socketStream.setVersion(QDataStream::Qt_5_6);</tt> makes sure that clients compiled with different versions of Qt all communicate in the same way.
<tt>receiveJson</tt> is just slightly more involved: since <tt>readyRead</tt> is emitted when there is '''some''' data available to read but not necessarily '''all''' of it, we start a transaction.
We then start an infinite loop that keeps trying to read JSON data. If the data was read correctly, <tt>commitTransaction</tt> will return true and we proceed with parsing the JSON into a <tt>QJsonDocument</tt> otherwise we just stop and wait for more data to arrive.

Revision as of 16:36, 31 May 2018

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. We'll implement 2 versions of the server, one that runs in a single server and one that distributes the sockets among multiple threads.