Qt写群聊项目(二):客户端

依旧先从头文件看整体

cpp 复制代码
#ifndef GROUPCHAT_H
#define GROUPCHAT_H

#include <QMainWindow>
#include<QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui {
class GroupChat;
}
QT_END_NAMESPACE

class GroupChat : public QMainWindow
{
    Q_OBJECT

public:
    GroupChat(QWidget *parent = nullptr);
    ~GroupChat();
    void start(const QString& host,quint16 port);

private slots:
    void on_pushButton_clicked();
    void slot_connected();
    void slot_disconnected();
    void slot_errorOccurred(QAbstractSocket::SocketError socketError);
    void slot_readyRead();

private:
    Ui::GroupChat *ui;
    QTcpSocket*m_client;

};
#endif // GROUPCHAT_H

1. 类继承与 UI 结构

  • QMainWindow:表明这是一个主窗口程序。客户端需要显示聊天记录列表、输入框、发送按钮等,这些都属于 UI 部分。
  • Ui::GroupChat *ui :这是 Qt 机制自动生成的界面类指针。通过 ui->pushButtonui->textEdit 等方式,你可以在代码中操作在 .ui 设计文件里画好的界面元素。
  • QTcpSocket *m_client
    • 核心区别 :服务器端维护了一个 QList<QTcpSocket*> 来管理很多用户,而客户端通常只需要一个 QTcpSocket
    • 这个 m_client 负责与服务器建立唯一的 TCP 连接,所有的消息收发都通过它完成。

2. 公共接口

复制代码
void start(const QString& host, quint16 port);
  • 启动连接 :类似于服务器的 start,这个函数用于让客户端尝试连接到指定的服务器 IP 和端口。

3. 私有槽函数

这里的槽函数分为两类:界面交互网络状态

A. 界面交互
复制代码
void on_pushButton_clicked(); // <--- 自动关联的槽
  • 命名规则 :在 Qt 中,如果你在 UI 设计器里给按钮起名叫 pushButton,Qt 会自动将它的点击信号连接到 on_pushButton_clicked() 这个函数上(前提是遵循特定的命名规则)。
  • 逻辑推断 :这通常是"发送"按钮。用户点击后,代码会从输入框获取文本,并通过 m_client->write() 发送给服务器。
B. 网络状态与数据处理

这四个槽与服务器端的逻辑非常相似,只是视角从"管理者"变成了"参与者":

  1. void slot_connected()

    触发时机 :当 m_client 成功连接到服务器时。

  2. void slot_disconnected()

    触发时机:与服务器的连接断开时。

  3. void slot_errorOccurred(...)

    触发时机:连接出错(如服务器没开、网络不通)。

  4. void slot_readyRead()

    触发时机:收到服务器发来的数据时。

与服务器的总结对比

特性 服务器 (GroupChatServer) 客户端
基类 QObject (后台逻辑) QMainWindow (有界面)
网络对象 QTcpServer + 多个 QTcpSocket 单个 QTcpSocket
主要任务 监听、管理连接、转发消息 连接服务器、显示消息、发送用户输入
readyRead 逻辑 读数据 -> 遍历列表转发给其他人 读数据 -> 追加显示到聊天窗口

下面是核心函数的具体实现:

1. 初始化与自动连接

cpp 复制代码
GroupChat::GroupChat(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::GroupChat)
    ,m_client(new QTcpSocket(this))
{
    ui->setupUi(this);
    start("127.0.0.1",6666);
}

GroupChat::~GroupChat()
{
    delete ui;
}

void GroupChat::start(const QString &host, quint16 port)
{
    m_client->connectToHost(QHostAddress(host),port);
    connect(m_client,&QTcpSocket::connected,this,&GroupChat::slot_connected);
    connect(m_client,&QTcpSocket::disconnected,this,&GroupChat::slot_disconnected);
    connect(m_client,&QTcpSocket::errorOccurred,this,&GroupChat::slot_errorOccurred);
    connect(m_client,&QTcpSocket::readyRead,this,&GroupChat::slot_readyRead);
}
  • 自动连接 :只要你启动客户端程序,它就会立刻去连接 127.0.0.1(本机)的 6666 端口。
  • 信号绑定 :绑定了 readyRead 等信号,意味着一旦服务器发来数据,或者连接状态改变,客户端就会自动响应。

2. 发送消息:UI + 网络 (on_pushButton_clicked)

这是用户点击"发送"按钮后的逻辑,这里有一个非常有意思的设计细节:

cpp 复制代码
void GroupChat::on_pushButton_clicked()
{
    auto msg = ui->sendedit->toPlainText(); // 1. 获取输入框内容
    auto dt = QDateTime::currentDateTime().toString("yyyy-mm-dd hh:mm:ss");
    
    // 2. 【关键步骤】立刻显示在自己的屏幕上
    ui->showedit->insertPlainText(QString("[%1]:%2").arg(dt).arg(msg+"\n"));
    
    // 3. 发送给服务器
    m_client->write(msg.toUtf8());
}

为什么要自己在界面上显示一遍?

因为服务器收到消息后,只会转发给其他人 ,而不会把消息发回给发送者。所以,客户端必须在点击发送的瞬间,把自己说的话直接"贴"到聊天记录显示框(showedit)里。如果不这样做,你自己说的话是永远看不到的。

3. 接收消息:显示他人发言 (slot_readyRead)

cpp 复制代码
void GroupChat::slot_readyRead()
{
    auto msg = m_client->readAll(); // 读取服务器转发来的数据
    auto dt = QDateTime::currentDateTime().toString("yyyy-mm-dd hh:mm:ss");
    // 将别人的消息显示在屏幕上
    ui->showedit->insertPlainText(QString("[%1]:%2").arg(dt).arg(msg+"\n"));
}
  • 逻辑 :当别人在群里说话时,服务器会把消息转发给这个客户端。readyRead 触发,读取数据并追加显示到界面。
相关推荐
轩情吖2 小时前
数据结构-并查集
开发语言·数据结构·c++·后端··并查集
wjs20242 小时前
SQL CREATE DATABASE 命令详解
开发语言
独自破碎E2 小时前
LCR001-两数相除
java·开发语言
YYYing.2 小时前
【Linux/C++进阶篇 (一)】man手册、gdb调试、静态库与动态库
linux·运维·c++
孞㐑¥2 小时前
算法—模拟
c++·经验分享·笔记·算法
70asunflower2 小时前
Python网络内容下载框架教程
开发语言·网络·python
微祎_2 小时前
Flutter for OpenHarmony:构建一个专业级 Flutter 番茄钟,深入解析状态机、定时器管理与专注力工具设计
开发语言·javascript·flutter
2401_891450462 小时前
C++中的职责链模式实战
开发语言·c++·算法
m0_708830962 小时前
C++中的原型模式变体
开发语言·c++·算法