QT聊天室基于Tcp

news2024/11/26 4:44:18

 

server.cpp

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    ,server(new QTcpServer(this)) // 给服务器指针对象实例化空间


{
    ui->setupUi(this);
}

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

//启动服务器按钮对应的槽函数
void Widget::on_startBtn_clicked()
{
    //获取ui界面上的端口号
    quint16 port = ui -> portEdit -> text().toUInt();
    //服务器设置监听
    //    bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
    //    参数1:监听的地址,指定的主机,或任意
    //    参数2:监听的端口号,可以是指定,也可是系统提供
    bool ret = server -> listen(QHostAddress::Any, port);
    if(ret == false){
        QMessageBox::information(this, "", "启动服务器失败");
        return;
    }
    ui -> startBtn -> setText("已启动");

    //此时若有客户端发来连接请求,那么服务器就会自动发射一个newConnect()信号
    //我们就可以将该信号连接到自定义的槽函数中,获取客户端的套接字
    connect(server, &QTcpServer::newConnection, this, &Widget::new_connection_slot);



}

//有新的客户端连接 connect 对应的槽函数
void Widget::new_connection_slot()
{
    //连接最先连接的客户端套接字
    // virtual QTcpSocket *nextPendingConnection();
    //返回值客户端的套接字
    QTcpSocket * s = server -> nextPendingConnection();

    //将获取到的客户端放入客户端容器中 尾插
    socketList.push_back(s);

    //程序运行至此,客户端和服务端成功建立了连接
    //若客户端发来数据,那么客户端就会自动发送一个readyRead()函数
    //
    connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}

//readyRead()信号对应的槽函数
void Widget::readyRead_slot()
{
    //遍历客户端容器,移除无效客户端
    for(int i = 0; i < socketList.count(); i++){
        if(socketList.at(i) -> state() == 0){
            //移除无效客户端
            socketList.removeAt(i);
            i--;
        }
    }

    //读取发来的数据
    for (int i = 0; i < socketList.count(); i++) {
        //判断客户端是否有数据待读
        //bytesAvailable();
        if(socketList.at(i) -> bytesAvailable() != 0){
            //读取数据
            QByteArray msg = socketList.at(i) -> readAll();

            //将读取的数据放入ui界面
            ui -> listWidget -> addItem(QString::fromLocal8Bit(msg));

            //将数据广播给所有的客户端
            for (int j = 0; j < socketList.count(); j++) {
                //不发送信息到发送信息的客户端
                if(i == j){continue;}

                socketList.at(j) -> write(msg);
            }
        }
    }
}

 sever.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket> //客户端的类
#include <QMessageBox>
#include <QList> // 链表容器


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 on_startBtn_clicked();
    void new_connection_slot();
    void readyRead_slot();

private:
    Ui::Widget *ui;
    QTcpServer *server;

    //定义一个存放客户端的容器
    //template <typename T>
    //class QList
    QList<QTcpSocket *> socketList;
};
#endif // WIDGET_H

 client.cpp

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    ,socket(new QTcpSocket(this))       //给客户端实例空间 ,指定父对象this
{
    ui->setupUi(this);
    //初始化界面
    ui -> usrEdit -> setText("风呤");
    ui -> portEdit -> setText("8888");
    ui -> ipEdit -> setText("192.168.127.22");

    ui -> msgEdit -> setEnabled(false);
    ui -> sendbtn -> setEnabled(false);
    ui -> disLinkEdit -> setEnabled(false);
//    ui -> listWidget -> setMaxLength();
    //设置文本自动换行
    ui -> listWidget -> setWordWrap(true);
    connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);
    connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnect_slot);

}

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

//连接服务器按钮对应的槽函数
void Widget::on_linkBtn_clicked()
{
    //获取ui界面上的ip和端口号
    QString ip = ui -> ipEdit -> text();
    quint16 port = ui -> portEdit -> text().toUInt();
   //让客户端连接服务器
    //virtual void connectToHost(const QString &hostName, quint16 port,
    //OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
    socket -> connectToHost(ip, port);

    //若成功连接服务器,那么客户端就会发送一个connected()信号
    //那么我们就可以将该信号连接到自定义的槽函数中处理逻辑代码,由于只需连接一次,故连接函数可写入构造函数中

    connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}

void Widget::connected_slot()
{
    //告诉服务器我来了
    usrname = ui -> usrEdit -> text();
    QString msg = usrname + ":已进入聊天室";

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

    //连接服务器成功
    QMessageBox::information(this, "", "已连接");

    //组件可用的相关设置
    ui -> msgEdit -> setEnabled(true);
    ui -> sendbtn -> setEnabled(true);
    ui -> disLinkEdit -> setEnabled(true);

    ui -> ipEdit -> setEnabled(false);
    ui -> linkBtn -> setEnabled(false);
    ui -> portEdit -> setEnabled(false);
    ui -> usrEdit -> setEnabled(false);

        //程序运行到此,说明客户端成功与服务器建立连接,若服务器发来数据,那么客户端就会自动发射一个readyRead信号
        //我们就可以将该信号连接到自定义的槽函数,读取数据,
}

void Widget::disconnect_slot()
{
    ui -> msgEdit -> setEnabled(false);
    ui -> sendbtn -> setEnabled(false);
    ui -> disLinkEdit -> setEnabled(false);

    ui -> ipEdit -> setEnabled(true);
    ui -> linkBtn -> setEnabled(true);
    ui -> portEdit -> setEnabled(true);
    ui -> usrEdit -> setEnabled(true);
}

void Widget::readyRead_slot(){
    //
    QByteArray msg = socket -> readAll();
    //
    ui -> listWidget -> addItem(QString::fromLocal8Bit(msg));

}

//发送按钮对应的槽函数
void Widget::on_sendbtn_clicked()
{
    //获取ui界面上的信息
    QString msg = ui -> msgEdit -> text();
    QString msg1 = msg + ":" + usrname;
    msg = usrname +  ":" + msg;

    //发送给服务器
    socket -> write(msg.toLocal8Bit());

    //将发送的文本输出到listWidget中
    QListWidgetItem * item= new QListWidgetItem(msg1);
    ui-> listWidget -> addItem(item);
    item->setTextAlignment(Qt::AlignRight);//右对齐
    //清空行编辑器
    ui -> msgEdit -> clear();
}

void Widget::on_disLinkEdit_clicked()
{
    //告诉服务器断开连接
    QString msg = usrname + ":已离开";

    socket -> write(msg.toLocal8Bit());

    socket -> disconnectFromHost();

    //若成功断开,那么客户端就会发送一个disconnected信号
    //我们就可以将该信号连接到自定义的槽函数

}

 client.h

#ifndef WIDGET_H
#define WIDGET_H

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

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_linkBtn_clicked();
    void connected_slot();
    void disconnect_slot();
    void readyRead_slot();
    void on_sendbtn_clicked();

    void on_disLinkEdit_clicked();


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

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

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

相关文章

集团数字化转型方案(一)

集团数字化转型方案通过系统集成先进的物联网&#xff08;IoT&#xff09;、大数据分析、人工智能&#xff08;AI&#xff09;和云计算技术&#xff0c;构建一个全面智能化的运营生态系统&#xff0c;涵盖从数据驱动的决策支持、智能化业务流程优化、到全渠道客户体验提升的各个…

【算法基础实验】图论-最小生成树-Prim的即时实现

理论知识 Prim算法是一种用于计算加权无向图的最小生成树&#xff08;MST, Minimum Spanning Tree&#xff09;的贪心算法。最小生成树是一个连通的无向图的子图&#xff0c;它包含所有的顶点且总权重最小。Prim算法从一个起始顶点开始&#xff0c;不断将权重最小的边加入生成…

CTFHUB | web进阶 | JSON Web Token | 无签名

一些JWT库也支持none算法&#xff0c;即不使用签名算法。当alg字段为空时&#xff0c;后端将不执行签名验证 开启题目 账号密码随便输&#xff0c;登录之后显示只有 admin 可以获得 flag 在此页面抓包发到 repeater&#xff0c;这里我们需要用到一个 Burp 插件&#xff0c;按图…

科研绘图配色大全

目录 01 颜色网站 1.1 Material 1.1.1 tailwindcolor 1.2 Trending Color Palettes1.3 Material Palette 1.4 Graphs Colors 1.5 RGB颜色值与十六进制颜色码转换 1.6 colorbrewer 1.7 优设 1.8 Chinese Colors1.9 handpicked colors 02 科研绘图配色方案 2.1 常见科技…

干货:2024必备的四大PDF编辑器推荐!

面对PDF文件的编辑需求&#xff0c;你是否感到无从下手&#xff1f;那么&#xff0c;今天就为大家推荐几款实用的PDF编辑工具&#xff0c;让你轻松应对各种PDF编辑难题。 福昕PDF编辑器 链接&#xff1a;editor.foxitsoftware.cn 福昕PDF编辑器多功能专业级是我PDF编辑器。它…

【C++例题 / 训练】二分算法(模板 例题)

引言 二分也就是二分查找&#xff0c;又叫折半查找。这种算法正如其名&#xff0c;每一次都要分一半。 二分算法可以分为二分查找和二分答案。 以在一个升序数组中查找一个数为例&#xff0c;每次考察数组当前部分的中间元素&#xff0c;如果中间元素刚好是要找的&#xff0…

王牌功能 | 法大大“证据管理”,让关键数据坚不可摧!

到底还能不能好好签合同… 法大大证据管理功能&#xff0c;基于电子合同签署全流程&#xff0c;为使用法大大电子签的机构及个人用户提供互联网数据电文的实时存证&#xff0c;并由第三方机构进行证据固化&#xff0c;将存证的数据电文转化成可读性更高、具有司法效力的证明材料…

多线程、多进程,还是异步?-- Python 并发 API 如何选择

如何选择正确的 Python 并发 API模块 &#xff1f; Python 标准库提供了三种并发 API &#xff0c; 如何知道你的项目应该使用哪个 API&#xff1f; 在本教程将带逐步了解各API的特性、区别以及各自应用场景&#xff0c;指导你选择最合适的并发 API。 多线程、多进程&#xff0…

音频采集spring_ws_webrtc (html采集麦克风转gb711并发送广播播放)完整案例

下载地址&#xff1a;http://www.gxcode.top/code 项目说明 springbootwebscoektwebrtc 项目通过前端webrtc采集麦克风声音&#xff0c;通过websocket发送后台&#xff0c;然后处理成g711-alaw字节数据发生给广播UDP并播放。 后台处理项目使用线程池(5个线程)接受webrtc数据并…

JAVA基础:字节字符转换流

前言 当我们使用流读取数据时&#xff0c;如果这个数据中含有中文&#xff0c;我们对这个数据进行操作就会出现乱码问题&#xff0c;这时候我们要使用字节字符转换流来处理一下数据。 字节字符转换流 字节字符转换流是一个过程流 字节字符转换流是一个字符流&#xff0c;所…

如何为 SEO 做关键词优化

关键词优化是一种基本的 SEO 技术&#xff0c;可以提高你的网站在搜索结果中的可见度&#xff0c;并吸引更多的访问者。 在这份关键词优化指南中&#xff0c;我们将分享在 SEO 的这一方面脱颖而出所需的知识、技巧和技巧。使用本指南可以超越您的竞争对手&#xff0c;并为您的…

一文搞懂数据标注

hihi,大家好,最近开始和内容那个团队研究SD出图了,作为家具家电行业的小牛人,除了研究SD和ComfyUI本身,需要了解算法同学如何进行模型微调的,因为用的是开源的底座,预训练部分就不深入介绍了,重点看一下二次预训练,在这个过程中有一个环节比较关注就是小规模数据集,也…

【java】RuoYi-Vue前后端分离版本-请求被拦截,怎么修改拦截过滤器,解决方案

【java】RuoYi-Vue前后端分离版本-请求被拦截&#xff0c;怎么修改拦截过滤器 它用到了一个安全管理框架Spring Security 你可以通过这篇文章《Spring Security 详解》 去了解它&#xff0c;怎么使用或者使用原理。 所有业务都受SecurityConfig配置所过滤 SecurityConfig配置…

2024年思维导图工具怎样可以轻松选择

思维导图&#xff0c;作为一种直观、有效的思维工具&#xff0c;凭借其强大的信息整理能力和创意激发潜力&#xff0c;逐渐成为了人们学习、工作和生活中不可或缺的一部分。今天&#xff0c;就让我们一起走进这个充满智慧的领域&#xff0c;探索那些2024年大家都在使用的思维导…

Cleer耳机好不好用?南卡、Cleer、飞利浦、倍思横评对比

​大家好&#xff0c;作为一位多年的数码博主和耳机发烧友&#xff0c;最近后台收到不少私信&#xff0c;都是小伙伴想让我测评一下最近很火热的开放式耳机&#xff0c;那么为了回馈大家这么久的支持&#xff0c;说做就做&#xff01;我买了最近网上很热门的几款开放式耳机&…

电线 硬线 和软线 连接

电线 硬线 和软线 连接 首先把软线&#xff0c;拧成一股&#xff0c;然后搭到硬线上回转一圈&#xff0c;这里要注意线头往反向回转&#xff0c;大家看下图中的软线&#xff0c; 再在硬线上缠绕7—8圈&#xff0c;根据线的长短&#xff0c;过长就剪去一些。 最后将硬导线往后弯…

【速览】设计模式(更新中)

目录 一、背景二、优缺点优点缺点 三、适用场景四、核心组成创建型模式 Creational Design Pattern 5结构型模式 Structural Design Patterns 7行为型模式 Behavioral Design Patterns 11’ 五、底层原理六、对比参考 一、背景 这个技术出现的背景、初衷和要达到什么样的目标或…

【Python开发实践】在线商城系统——需求及需求分析

项目背景及需求 这个练习项目的设置背景是一家图书销售公司&#xff0c;为了扩大销售渠道&#xff0c;想要开通网上商城&#xff0c;利用在线博客和电子商城来销售图书。 具体需求如下&#xff1a; 每个商品可以留言 实现在线购物车处理和订单处理 实现对产品、购物车和订单的…

python | 图片转换为 pdf 实现方法

目录 一、PIL 库简介及安装使用方法 &#xff08;一&#xff09;python 不同版本下 PIL 的使用方法 二、图片转换为 pdf 的两种实现方法 &#xff08;一&#xff09;简易版——pdf 页面尺寸跟随图片大小 &#xff08;二&#xff09;常用版——pdf 每页尺寸统一为 A4 一、P…

C#PACS系统源码,影像存档与传输系统源码,数字化医学影像系统源码,三维重建影像PACS系统源码

C#PACS系统源码&#xff0c;影像存档与传输系统源码&#xff0c;数字化医学影像系统源码&#xff0c;三维重建影像PACS系统源码 PACS即影像存档与传输系统&#xff08;Picture Archiving and Communication System&#xff09;&#xff0c;是医学影像、数字化图像技术、计算机技…