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

news2024/11/13 4:10:29

服务段头文件

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129615.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计一个算法,找出由str1和str2所指向两个链表共同后缀的起始位置

假定采用带头结点的单链表保存单词&#xff0c;当两个单词有相同的后缀时&#xff0c;则可共享相同的后缀存储空间&#xff0c;例如&#xff0c;’loading’和’being’的存储映像如下图所示。 设str1和str2分别指向两个单词所在单链表的头结点&#xff0c;链表结点结构为 data…

HashTable哈希表

概念 散列表(Hash Table)&#xff0c;又称哈希表。是一种数据结构&#xff0c;特点是:数据元素的关键字与其存储地址直接相关 在顺序结构以及树型结构中&#xff0c;数据元素的关键字与其存储位置没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经过关键码…

KV260 进阶开发(PYNQ驱动开发+Pixel Pack)

目录 1. 简介 2. PixelPacker HLS 实现 2.1 PixelPacker HLS 源码 2.2 PixelPacker 功能简介 2.3 头文件介绍 2.4 启动间隔 II 2.5 Case V24 片段解释 3. PixelPacker Py 驱动 3.1 PixelPacker Py 源码 3.2 PixelPacker 类详解 3.3 property 装饰器 3.4 操作寄存器…

一、(JS)JS中鼠标事件-mouseenter、mouseleave和mouseover、mouseout区别

一、单个元素下mouseenter、mouseleave和mouseover、mouseout没有区别 我们先来一个demo&#xff0c;设置一个div <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"…

INIC6081量产工具下载,initio6081开卡软件分享

国内固态硬盘常用&#xff0c;且有量产工具流传出来的主控厂商包括慧荣、群联、点序、英韧、得一微、瑞昱、联芸、迈威、国科、华澜微等等。 每个主控需要用各自对应的量产工具&#xff0c;不同的量产工具支持的闪存颗粒也有差异&#xff0c;因此要根据固态硬盘实际的主控型号…

基于SSM的酒店客房管理系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

Visual Studio 设置文件默认编码格式、行尾符等

文章目录 1.命令方式2.EditorConfig配置 1.命令方式 2.EditorConfig配置 微软官方文档 使用EditorConfig方式配置&#xff0c;无需Visual Studio软件自带对EditorConfig的支持&#xff0c;无需插件 将下面.editorconfig文件放在项目根目录下 root true # 所在目录是根目录…

基于SSM的二手交易管理系统的设计与实现 (含源码+sql+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的二手交易管理系统1拥有两种角色 管理员&#xff1a;商品管理、订单管理、充值管理、用户管理等用户&#xff1a;发布商品、查看闲置、充值账户、查看所有订单、发布求购信息、修…

今年白银市场的供需关系矛盾

自从2020年以来&#xff0c;白银手持连续4年都出现了供需缺口&#xff0c;预计今年的供需缺口将进一步扩大。2015年以来&#xff0c;白银总产量始终维持10亿盎司水平上下波动&#xff0c;2015~2023年的年均复合增速在0.4%&#xff0c;预计2024年的产量将下降1%。矿产银的产量从…

day-54 求出最多标记下标

思路 假设nums的长度为len&#xff0c;则返回数最大最大为&#xff08;len/2&#xff09;*2,所以可以将数组分为两部分&#xff0c;[0(len-1)/2]为一部分&#xff0c;[(len-1&#xff09;/2len-]为第二部分 解题过程 指针right从第二部分从右向左开始遍历&#xff0c;指针left…

Tensorboard 基础与使用-——界面介绍

在导入运行tensorboard得到一个event file文件。 tensorboard基本原理是这样的 python代码中将可视化的数据记录到event file中&#xff0c;保存至硬盘 采用tensorboard对event file文件进行读取&#xff0c;并在web端进行可视化 指令启动&#xff1a; tensorboard --logdir…

大数据Flink(一百一十七):Flink SQL的窗口操作

文章目录 Flink SQL的窗口操作 一、窗口的概述 二、Group Windows 1、​​​​​​​滚动窗口&#xff08;TUMBLE&#xff09; 2、​​​​​​​​​​​​​​滑动窗口&#xff08;HOP&#xff09; 3、​​​​​​​​​​​​​​Session 窗口&#xff08;SESSION&am…

军事目标无人机视角检测数据集 3500张 坦克 带标注voc

数据集概述 该数据集包含3500张无人机拍摄的图像&#xff0c;主要用于坦克目标的检测。数据集已经按照VOC&#xff08;Visual Object Classes&#xff09;标准进行了标注&#xff0c;适用于训练深度学习模型&#xff0c;特别是物体检测模型。 数据集特点 目标明确&#xff1…

通信工程学习:什么是GFP通用成帧规范

GFP&#xff1a;通用成帧规范 GFP通用成帧规范&#xff08;Generic Framing Procedure&#xff09;是一种先进的数据业务适配的通用协议和映射技术&#xff0c;由国际电联ITU-T的G.7041标准定义。该技术旨在透明地将各种不同物理层或逻辑链路层信号适配进入SDH&#xff08;同步…

C语言初识编译和链接

目录 翻译环境和运行环境编译环境预编译编译词法分析语法分析语义分析 汇编 链接运行环境 翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指令&#xff08;⼆进制指令&…

【Vue】1.v-指令、computed、watch

1 Vue 实例 注&#xff1a;此文件是 vue 根实例&#xff0c;data 可以 是一个对象 即 data:{ } 但是在其他 .vue 组件文件中&#xff0c;data 必须 是一个函数&#xff0c;返回一个新的对象&#xff0c;以避免多个组件实例之间的数据相互干扰 即 data(){ } <!DOCTYPE html&g…

前端正确设置资源上下文路径ContextPath(发布目录outDir 、公共基础路径),保证打包部署后站点能正常加载资源。

文章目录 引言I 处理资源上下文路径ContextPathjavascript对象获取上下文路径使用`./` 加载资源文件Vite 的basepublicPath是webpack部署应用包时的基本 URLII 知识扩展:URL的识别2.1 标准的链接格式2.2 URL中的?涵义2.3 URL中的&涵义2.4 传参III #fragment3.1为网页位置…

Vue2使用Vue CLI学习笔记

Vue2构建项目分析 Vue学习官网 Vue CLI官方 # 全局安装&#xff0c;只要装一次&#xff0c;以管理员身份 npm install -g vue/cli # 查看脚手架工具版本 vue --version # 创建项目&#xff0c;注意路径&#xff0c;名称不能是中文 vue create my-project # 启动项目&#xff…

基于Ant-Design-Vue设计的配置化表单

适用vue 3.4 版本以上 在日常的前端开发中&#xff0c;表单开发必不可少&#xff0c;尤其是在遇到一些大型的复杂的表单&#xff0c;这往往会变成一个痛点。于是就想着开发一个可以list来配置的表单组件。 先上组件代码 <!-- 该组件 VUE 版本在 3.4 以上可使用--> <…

【AI绘画】Midjourney进阶:景别详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;为什么要学习景别景别的作用景别应用实例 &#x1f4af;大景别&#x1f4af;远景特点提示词书写技巧测试 &#x1f4af;全景特点提示词书写技巧测试注意点 &#x1f…