【Qt初入江湖】Qt 聊天室 示例实现

鱼弦:CSDN内容合伙人、CSDN新星导师、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

Qt聊天室是一个基于网络通信的实时聊天软件,它通常由客户端和服务器端两部分组成。在本文中,我们将详细介绍Qt聊天室的底层架构、原理和实现方法。

Qt聊天室的底层架构由以下几个部分组成:

  1. QTcpServer

QTcpServer是Qt中用于实现TCP服务器的类,它可以监听指定的端口,等待客户端的连接请求。在Qt聊天室中,我们可以使用QTcpServer来监听客户端的连接请求。

  1. QTcpSocket

QTcpSocket是Qt中用于实现TCP客户端的类,它可以连接到指定的服务器,并发送和接收数据。在Qt聊天室中,我们可以使用QTcpSocket来连接到服务器,并发送和接收聊天消息。

  1. QThread

QThread是Qt中用于实现线程的类,它可以将任务分配到不同的线程中执行。在Qt聊天室中,我们可以使用QThread将网络通信和UI更新分别执行,以避免UI线程被阻塞。

  1. QDataStream

QDataStream是Qt中用于实现数据流的类,它可以将数据序列化为二进制流,也可以将二进制流反序列化为数据。在Qt聊天室中,我们可以使用QDataStream将聊天消息序列化为二进制流,并发送给服务器或其他客户端。

下面是一个简单的基于 TCP 的聊天室的实现架构图:

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

在这个架构中,ServerSocket 类继承自 QTcpServer 类,它负责监听客户端的连接请求并创建对应的客户端套接字。当有新的客户端连接时,ServerSocket 会创建一个新的 ClientSocket 对象(继承自 QTcpSocket 类)来处理与客户端的通信。ClientSocket 类中的槽函数用于接收客户端发送的消息并广播给其他客户端。

在Qt聊天室中,我们可以使用以下方法来实现聊天功能:

  1. QTcpServer::listen()

listen()方法用于开始监听指定的端口,它接受一个整数类型的参数,表示要监听的端口号。例如:

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

newConnection()信号在有新的客户端连接请求时触发,我们可以在该信号的槽函数中创建新的QTcpSocket对象,并将其连接到客户端。例如:

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

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

connectToHost()方法用于连接到指定的服务器,它接受一个字符串类型的参数,表示要连接的服务器的主机名或IP地址,以及一个整数类型的参数,表示要连接的服务器的端口号。例如:

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

connected()信号在成功连接到服务器时触发,我们可以在该信号的槽函数中发送登录消息给服务器。例如:

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

readyRead()信号在有数据可读时触发,我们可以在该信号的槽函数中接收聊天消息,并将其显示在UI上。例如:

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

disconnected()信号在与服务器的连接断开时触发,我们可以在该信号的槽函数中清理相关资源。例如:

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

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

start()方法用于启动线程,它会自动调用线程的run()方法。例如:

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

operator<<()方法用于将数据序列化为二进制流,operator>>()方法用于将二进制流反序列化为数据。例如:

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

// ...

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

下面是一个简单的Qt聊天室的实现示例,其中包含了上述方法的使用:

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

在这个实现示例中,服务器和客户端分别由ChatServer类和ChatClient类

猜你喜欢

转载自blog.csdn.net/feng1790291543/article/details/131807334