[Qt ingresó por primera vez a ríos y lagos] Ejemplo de implementación de la sala de chat Qt

Yuxian: socio de contenido de CSDN, nuevo mentor estrella de CSDN, 51CTO (celebridad destacada + blogger experto), entusiasta del código abierto de github (desarrollo secundario del código fuente go-zero, arquitectura back-end del juego https://github.com/Peakchen)

 

Qt chat room es un software de chat en tiempo real basado en comunicación de red, que normalmente consta de dos partes: cliente y servidor. En este artículo, presentaremos en detalle la arquitectura subyacente, los principios y los métodos de implementación de la sala de chat Qt.

La arquitectura subyacente de la sala de chat Qt consta de las siguientes partes:

  1. Servidor QTcp

QTcpServer es una clase utilizada para implementar un servidor TCP en Qt. Puede escuchar un puerto específico y esperar una solicitud de conexión de un cliente. En la sala de chat de Qt, podemos usar QTcpServer para monitorear la solicitud de conexión del cliente.

  1. QTcpSocket

QTcpSocket es una clase utilizada para implementar un cliente TCP en Qt, que puede conectarse a un servidor específico y enviar y recibir datos. En la sala de chat Qt, podemos usar QTcpSocket para conectarnos al servidor y enviar y recibir mensajes de chat.

  1. hilo Q

QThread es una clase utilizada para implementar subprocesos en Qt, que puede asignar tareas a diferentes subprocesos para su ejecución. En la sala de chat de Qt, podemos usar QThread para realizar la comunicación de red y la actualización de la interfaz de usuario por separado para evitar bloquear el hilo de la interfaz de usuario.

  1. QDataStream

QDataStream es una clase utilizada para implementar flujos de datos en Qt. Puede serializar datos en flujos binarios y deserializar flujos binarios en datos. En la sala de chat de Qt, podemos usar QDataStream para serializar el mensaje de chat en una secuencia binaria y enviarlo al servidor u otros clientes.

El siguiente es un diagrama de arquitectura de implementación de una sala de chat simple basada en TCP:

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

En este marco, la clase ServerSocket hereda de la clase QTcpServer, que es responsable de monitorear la solicitud de conexión del cliente y crear el socket de cliente correspondiente. Cuando se conecta un nuevo cliente, ServerSocket creará un nuevo objeto ClientSocket (heredado de la clase QTcpSocket) para manejar la comunicación con el cliente. La función de ranura en la clase ClientSocket se utiliza para recibir el mensaje enviado por el cliente y transmitirlo a otros clientes.

En la sala de chat Qt, podemos utilizar los siguientes métodos para implementar la función de chat:

  1. QTcpServer::escuchar()

El método listening() se utiliza para comenzar a escuchar el puerto especificado y acepta un parámetro de tipo entero que indica el número de puerto que se va a escuchar. Por ejemplo:

QTcpServer server;
server.listen(QHostAddress::Any, 1234);
  1. QTcpServer::nuevaConexión()

La señal newConnection() se activa cuando hay una nueva solicitud de conexión del cliente. Podemos crear un nuevo objeto QTcpSocket en la función de ranura de la señal y conectarlo al cliente. Por ejemplo:

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

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

El método connectToHost() se utiliza para conectarse al servidor especificado, acepta un parámetro de tipo cadena, que indica el nombre de host o dirección IP del servidor a conectar, y un parámetro de tipo entero, que indica el número de puerto del servidor. estar conectado. Por ejemplo:

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

La señal conectada () se activa cuando nos conectamos exitosamente al servidor, y podemos enviar un mensaje de inicio de sesión al servidor en la función de ranura de la señal. Por ejemplo:

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()

La señal readyRead() se activa cuando hay datos para leer y podemos recibir mensajes de chat en la función de ranura de la señal y mostrarlos en la interfaz de usuario. Por ejemplo:

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::desconectado()

La señal desconectada () se activa cuando se desconecta la conexión con el servidor y podemos limpiar los recursos relacionados en la función de ranura de la señal. Por ejemplo:

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

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

El método start() se utiliza para iniciar el hilo y llamará automáticamente al método run() del hilo. Por ejemplo:

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::operador<<() y QDataStream::operador>>()

El método operador<<() se utiliza para serializar datos en un flujo binario, y el método operador>>() se utiliza para deserializar un flujo binario en datos. Por ejemplo:

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

// ...

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

El siguiente es un ejemplo de implementación de una sala de chat Qt simple, que incluye el uso de los métodos anteriores:

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();
}

En este ejemplo de implementación, el servidor y el cliente están representados por la clase ChatServer y la clase ChatClient respectivamente.

Supongo que te gusta

Origin blog.csdn.net/feng1790291543/article/details/131807334
Recomendado
Clasificación