关于QT服务端客户端的聊天

服务段头文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QTcpServer>
#include<QMessageBox>
#include<QDebug>
#include<QList>
#include<QTcpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public slots:
    void newConnection_slot();
    void readyRead_slot();

private slots:
    void on_startBtn_clicked();

private:
    Ui::Widget *ui;
    QTcpServer *server;
    QList<QTcpSocket *>socketList;
};
#endif // WIDGET_H

服务段测试文件

#include "widget.h"  
#include "ui_widget.h"  
#include "widget.h"  
#include "widget.h" 


Widget::Widget(QWidget *parent)
    : QWidget(parent)  
    , ui(new Ui::Widget)  
    ,server(new QTcpServer(this))  // 创建新的 QTcpServer 对象,指定当前对象为其父对象
{
    ui->setupUi(this);  
}


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

// 槽函数:有新连接时调用,处理新的客户端连接
void Widget::newConnection_slot()
{
    qDebug() << "有新客户连接。。。";  // 输出调试信息,表示有新客户端连接
    QTcpSocket *s = server->nextPendingConnection();  // 获取下一个等待处理的连接
    socketList.push_back(s);  // 将新连接的 socket 加入到 socketList 列表中
    connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);  // 连接 readyRead 信号,当有数据可读时,调用 readyRead_slot 函数
}

// 槽函数:有数据可读时调用,处理客户端数据
void Widget::readyRead_slot()
{
    // 遍历 socketList 列表,检查是否有断开连接的 socket
    for(int i = 0; i < socketList.count(); i++)
    {
        if(socketList.at(i)->state() == 0)  // 如果 socket 状态为 0,表示已断开连接
        {
            socketList.removeAt(i);  // 从列表中移除断开连接的 socket
        }
    }

    // 再次遍历 socketList,读取每个客户端的可用数据
    for(int i = 0; i < socketList.count(); i++)
    {
        if(socketList.at(i)->bytesAvailable() != 0)  // 如果当前 socket 有可用数据
        {
            QByteArray msg = socketList.at(i)->readAll();  // 读取所有可用数据并存储在 msg 中
            ui->listWidget->addItem(QString::fromLocal8Bit(msg));  // 将收到的消息转换为 QString 并添加到 listWidget 中显示
            // 将接收到的消息发送给其他所有客户端(除了当前客户端)
            for(int j = 0; j < socketList.count(); j++)
            {
                if(j != i)  // 确保不向发送消息的客户端回发消息
                {
                    socketList.at(j)->write(msg);  // 将消息写入其他客户端的 socket
                }
            }
        }
    }
}

// 槽函数:点击 "启动服务器" 按钮时调用,启动服务器监听指定端口
void Widget::on_startBtn_clicked()
{
    quint16 port = ui->portEdit->text().toUInt();  // 从用户界面的端口输入框中获取端口号,并转换为无符号整型
    if(server->listen(QHostAddress::Any, port))  // 服务器开始监听指定端口上的所有地址
    {
        QMessageBox::information(this, "", "启动服务器成功!");  // 弹出信息框,提示服务器启动成功
    }
    else
    {
        QMessageBox::information(this, "", "启动服务器失败!");  // 弹出信息框,提示服务器启动失败
        return;  // 如果启动失败,直接返回,不执行后续代码
    }
    connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);  // 连接服务器的新连接信号,处理新连接
}

客户端头文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


private slots:
    void on_connectBtn_clicked();
    void on_disconnectBtn_clicked();
    void on_sendBtn_clicked();

public slots:
    void connected_slot();
    void readyRead_slot();
    void disconnected_slot();

private:
    Ui::Widget *ui;
    QTcpSocket *socket;
    QString userName;
};
#endif // WIDGET_H

客户端测试文件

#include "widget.h"  
#include "ui_widget.h"  
#include "widget.h"  
#include "widget.h" 
#include "widget.h"  


Widget::Widget(QWidget *parent)
    : QWidget(parent)  
    , ui(new Ui::Widget)  
    , socket(new QTcpSocket(this))  // 创建 QTcpSocket 对象,用于连接服务器
{
    ui->setupUi(this);  
    ui->msgEdit->setEnabled(false);  // 禁用消息输入框,直到连接成功
    ui->sendBtn->setEnabled(false);  // 禁用发送按钮,直到连接成功
    ui->disconnectBtn->setEnabled(false);  // 禁用断开连接按钮,直到连接成功

    // 连接信号与槽
    connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);  // 当连接成功时,调用 connected_slot
    connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);  // 当有数据可读时,调用 readyRead_slot
    connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);  // 当断开连接时,调用 disconnected_slot
}


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

// 槽函数:处理服务器发送的数据
void Widget::readyRead_slot()
{
    QByteArray msg = socket->readAll();  // 读取服务器发来的所有数据
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));  // 将收到的消息显示在 listWidget 中
}

// 槽函数:点击 "连接" 按钮时触发,连接到服务器
void Widget::on_connectBtn_clicked()
{
    QString ip = ui->ipEdit->text();  // 获取用户输入的 IP 地址
    quint16 port = ui->portEdit->text().toUInt();  // 获取用户输入的端口号并转换为整数
    socket->connectToHost(ip, port);  // 连接到服务器
}

// 槽函数:处理连接成功的情况
void Widget::connected_slot()
{
    userName = ui->userEdit->text();  // 获取用户名
    QString msg = userName + ":进入聊天室";  // 构建进入聊天室的提示消息
    socket->write(msg.toLocal8Bit());  // 将消息发送到服务器

    QMessageBox::information(this, "", "连接服务成功!");  // 显示连接成功的提示框

    // 启用消息输入框、发送按钮和断开按钮
    ui->msgEdit->setEnabled(true);
    ui->sendBtn->setEnabled(true);
    ui->disconnectBtn->setEnabled(true);

    // 禁用用户名、IP 地址和端口号输入框,以及 "连接" 按钮
    ui->userEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectBtn->setEnabled(false);
}

// 槽函数:点击 "发送" 按钮时触发,发送消息到服务器
void Widget::on_sendBtn_clicked()
{
    QString msg = ui->msgEdit->text();  // 获取输入框中的消息
    msg = userName + ": " + msg;  // 将消息格式化为 "用户名: 消息"

    // 创建新的 QListWidgetItem 对象,用于显示发送的消息
    QListWidgetItem *item = new QListWidgetItem(msg);

    // 设置消息为右对齐(自己发送的消息)
    item->setTextAlignment(Qt::AlignRight);

    ui->listWidget->addItem(item);  // 将消息添加到 listWidget 中显示

    socket->write(msg.toLocal8Bit());  // 将消息发送到服务器

    ui->msgEdit->clear();  // 清空输入框
}

// 槽函数:点击 "断开" 按钮时触发,断开与服务器的连接
void Widget::on_disconnectBtn_clicked()
{
    QString msg = userName + ": 离开聊天室";  // 构建离开聊天室的提示消息
    socket->write(msg.toLocal8Bit());  // 将消息发送到服务器
    socket->disconnectFromHost();  // 断开与服务器的连接
}

// 槽函数:处理断开连接的情况
void Widget::disconnected_slot()
{
    // 禁用消息输入框、发送按钮和断开按钮
    ui->msgEdit->setEnabled(false);
    ui->sendBtn->setEnabled(false);
    ui->disconnectBtn->setEnabled(false);

    // 启用用户名、IP 地址和端口号输入框,以及 "连接" 按钮
    ui->userEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectBtn->setEnabled(true);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值