[Qt first entered the rivers and lakes] Qt chat room example implementation

Yuxian: CSDN content partner, CSDN new star mentor, 51CTO (Top celebrity + expert blogger), github open source enthusiast (secondary development of go-zero source code, game back-end architecture https://github.com/Peakchen)

 

Qt chat room is a real-time chat software based on network communication, which usually consists of two parts: client and server. In this article, we will introduce the underlying architecture, principles and implementation methods of the Qt chat room in detail.

The underlying architecture of the Qt chat room consists of the following parts:

  1. QTcpServer

QTcpServer is a class used to implement a TCP server in Qt. It can listen to a specified port and wait for a connection request from a client. In the Qt chat room, we can use QTcpServer to monitor the client's connection request.

  1. QTcpSocket

QTcpSocket is a class used to implement a TCP client in Qt, which can connect to a specified server and send and receive data. In the Qt chat room, we can use QTcpSocket to connect to the server and send and receive chat messages.

  1. QThread

QThread is a class used to implement threads in Qt, which can assign tasks to different threads for execution. In the Qt chat room, we can use QThread to perform network communication and UI update separately to avoid blocking the UI thread.

  1. QDataStream

QDataStream is a class used to implement data streams in Qt. It can serialize data into binary streams and deserialize binary streams into data. In the Qt chat room, we can use QDataStream to serialize the chat message into a binary stream and send it to the server or other clients.

The following is an implementation architecture diagram of a simple TCP-based chat room:

+-----------------+
|   ServerSocket  |
+-----------------+
| - tcpServer     |
| - clientSockets |
+-----------------+
          /_\
           |
           | 继承
           |
+-----------------+
|   QTcpServer    |
+-----------------+
          /_\
           |
           | 继承
           |
+-----------------+
|   QTcpSocket    |
+-----------------+

In this framework, the ServerSocket class inherits from the QTcpServer class, which is responsible for monitoring the client's connection request and creating the corresponding client socket. When a new client connects, ServerSocket will create a new ClientSocket object (inherited from QTcpSocket class) to handle the communication with the client. The slot function in the ClientSocket class is used to receive the message sent by the client and broadcast it to other clients.

In the Qt chat room, we can use the following methods to implement the chat function:

  1. QTcpServer::listen()

The listen() method is used to start listening to the specified port, and it accepts an integer type parameter indicating the port number to be listened to. For example:

QTcpServer server;
server.listen(QHostAddress::Any, 1234);
  1. QTcpServer::newConnection()

The newConnection() signal is triggered when there is a new client connection request. We can create a new QTcpSocket object in the signal's slot function and connect it to the client. For example:

QTcpServer server;
server.listen(QHostAddress::Any, 1234);

connect(&server, &QTcpServer::newConnection, [&]() {
    QTcpSocket *clientSocket = server.nextPendingConnection();
    // 将clientSocket添加到客户端列表中
});
  1. QTcpSocket::connectToHost()

The connectToHost() method is used to connect to the specified server. It accepts a parameter of string type, indicating the host name or IP address of the server to be connected, and an parameter of integer type, indicating the port number of the server to be connected. For example:

QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("127.0.0.1", 1234);
  1. QTcpSocket::connected()

The connected() signal is triggered when successfully connected to the server, and we can send a login message to the server in the slot function of the signal. For example:

QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("127.0.0.1", 1234);

connect(socket, &QTcpSocket::connected, [&]() {
    QByteArray username = "username";
    QByteArray password = "password";
    QDataStream stream(socket);
    stream << username << password;
});
  1. QTcpSocket::readyRead()

The readyRead() signal is triggered when there is data to read, and we can receive chat messages in the slot function of the signal and display them on the UI. For example:

QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("127.0.0.1", 1234);

connect(socket, &QTcpSocket::readyRead, [&]() {
    QDataStream stream(socket);
    QString message;
    stream >> message;
    // 将message显示在UI上
});
  1. QTcpSocket::disconnected()

The disconnected() signal is triggered when the connection with the server is disconnected, and we can clean up related resources in the slot function of the signal. For example:

QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("127.0.0.1", 1234);

connect(socket, &QTcpSocket::disconnected, [&]() {
    // 清理相关资源
});
  1. QThread::start()

The start() method is used to start the thread, and it will automatically call the thread's run() method. For example:

QThread *thread = new QThread;
MyNetworkWorker *worker = new MyNetworkWorker;

worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &MyNetworkWorker::run);
connect(worker, &MyNetworkWorker::finished, thread, &QThread::quit);
connect(worker, &MyNetworkWorker::finished, worker, &MyNetworkWorker::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);

thread->start();
  1. QDataStream::operator<<() 和 QDataStream::operator>>()

The operator<<() method is used to serialize data into a binary stream, and the operator>>() method is used to deserialize a binary stream into data. For example:

QByteArray username = "username";
QByteArray password = "password";
QDataStream stream(&buffer, QIODevice::WriteOnly);
stream << username << password;

// ...

QDataStream stream(socket);
QString message;
stream >> message;

The following is an implementation example of a simple Qt chat room, which includes the use of the above methods:

class ChatServer : public QObject
{
    Q_OBJECT

public:
    ChatServer(QObject *parent = nullptr) : QObject(parent)
    {
        server = new QTcpServer(this);
        connect(server, &QTcpServer::newConnection, this, &ChatServer::onNewConnection);
        server->listen(QHostAddress::Any, 1234);

        qInfo() << "Server started";
    }

signals:
    void messageReceived(QString message);

public slots:
    void onNewConnection()
    {
        QTcpSocket *clientSocket = server->nextPendingConnection();
        connect(clientSocket, &QTcpSocket::disconnected, clientSocket, &QTcpSocket::deleteLater);
        connect(clientSocket, &QTcpSocket::readyRead, this, &ChatServer::onMessageReceived);
        clients.append(clientSocket);
    }

    void onMessageReceived()
    {
        QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender());
        QDataStream stream(clientSocket);
        QString message;
        stream >> message;
        emit messageReceived(message);
    }

    void sendMessage(QString message)
    {
        QByteArray buffer;
        QDataStream stream(&buffer, QIODevice::WriteOnly);
        stream << message;

        for (QTcpSocket *clientSocket : clients) {
            clientSocket->write(buffer);
        }
    }

private:
    QTcpServer *server;
    QList<QTcpSocket*> clients;
};

class ChatClient : public QObject
{
    Q_OBJECT

public:
    ChatClient(QObject *parent = nullptr) : QObject(parent)
    {
        socket = new QTcpSocket(this);
        connect(socket, &QTcpSocket::connected, this, &ChatClient::onConnected);
        connect(socket, &QTcpSocket::disconnected, this, &ChatClient::onDisconnected);
        connect(socket, &QTcpSocket::readyRead, this, &ChatClient::onMessageReceived);
        socket->connectToHost("127.0.0.1", 1234);

        qInfo() << "Client started";
    }

public slots:
    void onConnected()
    {
        QByteArray username = "username";
        QByteArray password = "password";
        QDataStream stream(socket);
        stream << username << password;
    }

    void onDisconnected()
    {
        qInfo() << "Disconnected from server";
    }

    void onMessageReceived()
    {
        QDataStream stream(socket);
        QString message;
        stream >> message;
        qInfo() << "Received message:" << message;
    }

    void sendMessage(QString message)
    {
        QByteArray buffer;
        QDataStream stream(&buffer, QIODevice::WriteOnly);
        stream << message;
        socket->write(buffer);
    }

private:
    QTcpSocket *socket;
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    ChatServer server;
    ChatClient client;

    QObject::connect(&server, &ChatServer::messageReceived, &client, &ChatClient::sendMessage);
    QObject::connect(&client, &ChatClient::messageReceived, &server, &ChatServer::sendMessage);

    return app.exec();
}

In this implementation example, the server and client are represented by ChatServer class and ChatClient class respectively

Guess you like

Origin blog.csdn.net/feng1790291543/article/details/131807334