tcp的聊天室

news2024/12/25 9:16:08

注意:要加库文件,服务端客户端都要加 network

客户端的头文件

#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_sendbtn_clicked();

    void on_disconnectbtn_clicked();
    void on_connectbtn_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 <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

 客户端构造函数

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //初始化界面
    //设置按钮不可以状态
    ui->msgEdit->setEnabled(false);
    ui->sendbtn->setEnabled(false);
    ui->disconnectbtn->setEnabled(false);

    //给客户端指针实例化空间
    socket=new QTcpSocket(this);

    connect(socket,&QTcpSocket::connected,this,&Widget::connected_slot);

    //此时客户端和服务器已经建立连接,如果服务器发来数据,那么客户端就会自动发射 一个readyRead()信号
    //我们可以将该信号连接到自定义的槽函数中,读取服务器端的数据,又由只需要连接一次,在构造函数写连接

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

    //如果成功与服务器断开连接,那么该客户端就会自动发送一个disconnected信号
    //我们就可以将该信号连接到自定义函数中,处理逻辑代码,由于只要连接一次,所有在构造函数中连接

    connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnected_slot);
}

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

//连接服务器按钮对应的槽函数处理
void Widget::on_connectbtn_clicked()
{
    //获取ui界面上的ip和端口号
    QString ip=ui->ipEdit->text();
    quint16 port =ui->portEdit->text().toUInt();
    //将客户连接到服务器
    //参数1:主机地址
    //参数2:端口号
    socket->connectToHost(ip,port);

    //如果成功连接服务器,那么客户端将发送一个conneted信号
    //我们就可以将该信号连接到自定义的槽函数中处理逻辑代码,由于只需要连接一次,所有我们在构造函数中写连接

}


void Widget::connected_slot()
{
    QMessageBox::information(this,"","连接服务器成!");

    //告诉服务器,用户上线
    username =ui->userEdit->text();

    QString msg=username+": 进入聊天室";

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

    //将ui界面上的组件进行相关设置

    //可用状态
    ui->msgEdit->setEnabled(true);
    ui->sendbtn->setEnabled(true);
    ui->disconnectbtn->setEnabled(true);

    //不可以状态
    ui->userEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectbtn->setEnabled(false);

    //此时客户端和服务器已经建立连接,如果服务器发来数据,那么客户端就会自动发射 一个readyRead()信号
    //我们可以将该信号连接到自定义的槽函数中,读取服务器端的数据,又由只需要连接一次,在构造函数写连接

}

void Widget::readyRead_slot()
{
    //将服务器端的数据读取出来
    QByteArray msg =socket->readAll();

    //将数据放入ui界面上
    ui->msgWidget->addItem(QString::fromLocal8Bit(msg));
}


//disconnected信号对应的槽函数的实现
void Widget::disconnected_slot()
{
    QMessageBox::information(this,"","断开服务器成功");
    ui->msgEdit->setEnabled(false);
    ui->sendbtn->setEnabled(false);
    ui->disconnectbtn->setEnabled(false);

    ui->userEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectbtn->setEnabled(true);

}

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

    //整合信息
    msg=username+":"+msg;

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

    //清空发送框里的内容
    ui->msgEdit->clear();
}

//端口服务器按钮的槽函数处理
void Widget::on_disconnectbtn_clicked()
{
    //告诉大家我走了
    QString msg =username+":离开聊天室";

    //信息发送给服务器
    socket->disconnectFromHost();

    //如果成功与服务器断开连接,那么该客户端就会自动发送一个disconnected信号
    //我们就可以将该信号连接到自定义函数中,处理逻辑代码,由于只要连接一次,所有在构造函数中连接
}

客户端ui界面

 

服务端头文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QList> //链表容器
#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_staetBtn_clicked();
    void newConnection_solt(); //newconnection信号对应的槽函数
    void readyRead_slot();

private:
    Ui::Widget *ui;
    //定义服务器指针
    QTcpServer *server;


    //定义客户端容器
    QList<QTcpSocket *> socketList;

};
#endif // WIDGET_H

服务端主函数

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

服务的构造函数

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //给服务器指针实例化空间
    server =new QTcpServer(this);


}

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

//启动服务器按钮 对应的槽函数
void Widget::on_staetBtn_clicked()
{
    //获取ui界面上的端口号
    quint16 port = ui->portEdit->text().toInt();

   //将服务器设置监听状态
   //函数原型:bool
   //参数1:主机地址 可以是任意
    //参数2:端口号
    if(server->listen(QHostAddress::Any,port))
    {
        QMessageBox::information(this,"","启动服务器成功!");
    }
    else
    {
        QMessageBox::information(this,"","启动服务器失败!");
    }

    //此时说明服务器已经进入监听状态,如果有客户端发来连接请求,那么服务器端就会自动发射newconnection
    //将该信号连接到自定义的槽函数中,获取客户端的套接字
    connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_solt);
}

//newConnection信号对应槽函数处理
void Widget::newConnection_solt()
{
    qDebug() <<"有新的用户连接" ;

    //获取最新连接的客户端套接字
    //函数原型:virtual QTcpSocket *nextPendingConnection();
    //返回值:是客户端套接字的指针
    QTcpSocket *s =server->nextPendingConnection();

    //将套接字放入容器中
    socketList.push_back(s);

    //程序运行至此,说明服务端和客户端已经建立起联系,如果客户端发来数据,那么客户端就会自动发射readyrRead()信号
    //我们就可以将信号连接自定义的槽函数中,读取客户端的数据
    connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);


}
//readyRead信号对应槽函数声明
void Widget::readyRead_slot()
{
    //移除无效客户端
    //count :在容器中的所有元素个数
    for(int i=0;i<socketList.count();i++)
    {
        //函数原型:socketstate state() const
        if(socketList.at(i)->state()==0)
        {
            //移除
            socketList.removeAt(i);//将下表为i的 客户端移除

        }
    }

    //遍历有效客户端,寻找哪个客户端有数据待读
    for (int i=0;i<socketList.count();i++)
    {
        //函数原型:
        //判断是否有数据
        if(socketList.at(i)->bytesAvailable()!=0)
        {
            //读取套接字中的数据
            QByteArray msg = socketList.at(i)->readAll();

            //将数据放在ui界面上
            ui->msgWidget->addItem(QString::fromLocal8Bit(msg));

            //将数据广播给(发送)给所有客户端
            for(int j=0;j<socketList.count();j++)
            {
                //将数据写入到套接字中
                socketList.at(j)->write(msg);
            }

        }
    }
}

服务端ui界面

 

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

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

相关文章

js实现excel里面的PMT函数

// 辅助函数&#xff0c;保留两位小数function roundToTwoDecimal(value) {return Math.round(value * 100) / 100;}function calculatePMT(rate, nper, pv, fv, type) {// rate: 年利率// nper: 总期数// pv: 现值&#xff08;贷款或投资的初始金额&#xff09;// fv: 未来值&…

Leetcode—783.二叉搜索树节点最小距离【简单】

2023每日刷题&#xff08;五十八&#xff09; Leetcode—783.二叉搜索树节点最小距离 实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ void dfs(struct TreeNode* roo…

Next.js ts redux/toolkit状态管理

目录 介绍 安装依赖 初始化store 1、在src下创建store文件夹&#xff0c; 2、创建最简单的slice切片 3、创建入口文件index.ts 4、创建hooks.ts 在_app.tsx中注入store tsx中使用store payload createAsyncThunk 效果 介绍 reduxjs/toolkit是Redux 官方提供的一个…

C51--小车——L9110s电机驱动模块

电机模块开发&#xff1a; L9110s&#xff1a; 接通VCC&#xff0c;GND 模块电源指示灯亮。 IA1输入高电平&#xff0c;IA1输入低电平&#xff0c;【OA1 OB1】电机正转&#xff1b; IA1输入低电平&#xff0c;IA1输入高电平&#xff0c;【OA1 OB1】电机反转&#xff1b; IA2…

Java_Mybatis_动态SQL

一、动态SQL 1.概述 动态SQL&#xff1a; 是 MyBatis 的强大特性之一&#xff0c;解决拼接动态SQL时候的难题&#xff0c;提高开发效率分类 ifchoose(when,otherwise)trim(where,set)foreach 2.if 做 where 语句后面条件查询的,if 语句是可以拼接多条的 需求&#xff1a;根…

B站内容新爆点 | 高效引流、吸睛利器

11月29日&#xff0c;B站官方发布了2023年第三季度财报。财报显示&#xff0c;B站平台月均活跃用户数从第二季度3.24亿增长至3.41亿&#xff0c;再创新高&#xff0c;日均活跃用户数则突破一亿里程碑&#xff0c;达1.03亿&#xff0c;同比增长14%。用户日均使用时长首次超过100…

Java - Collectors.toMap() 使用

List 转 Map 一、Collectors.toMap() 函数源码定义&#xff1a; // 两个参数public static <T, K, U>Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper) {retu…

【数据结构】贪心算法

一.贪心算法的定义 贪心算法是指在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;只做出在某种意义上的局部最优解。 贪心算法的结果是最优解的最好近似。 优点&#xff1a;简单&#xff0c;高效。 缺点&…

慎用,Mybatis-Plus这个方法可能导致死锁

1 场景还原 1.1 版本信息 MySQL版本&#xff1a;5.6.36-82.1-log Mybatis-Plus的starter版本&#xff1a;3.3.2 存储引擎&#xff1a;InnoDB1.2 死锁现象 A同学在生产环境使用了Mybatis-Plus提供的 com.baomidou.mybatisplus.extension.service.IService#saveOrUpdate(T, co…

【MySQL】:表的约束(上)

表的约束 一.非空约束二.default约束三.列描述四.zerofill五.主键1.单个主键2.复合主键 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。比如有…

孩子还是有一颗网安梦——Bandit通关教程:Level 11 → Level 12

&#x1f575;️‍♂️ 专栏《解密游戏-Bandit》 &#x1f310; 游戏官网&#xff1a; Bandit游戏 &#x1f3ae; 游戏简介&#xff1a; Bandit游戏专为网络安全初学者设计&#xff0c;通过一系列级别挑战玩家&#xff0c;从Level0开始&#xff0c;逐步学习基础命令行和安全概念…

随机变量的定义

试验E的样本空间为S&#xff0c;样本空间S中的元素记为e&#xff0c;即样本点是e&#xff0c;样本空间记成&#xff0c;表示元素组成的集合。 随机变量的定义&#xff1a;设随机变量的样本空间为&#xff0c;是定义在样本空间S上的实值单值函数&#xff0c;称为随机变量。 随机…

螺旋矩阵算法(leetcode第54题)

题目描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a;输入&#xff…

《深入理解 Android ART 虚拟机》笔记

Dex文件格式、指令码 一个Class文件对应一个Java源码文件&#xff0c;而一个Dex文件可对应多个Java源码文件。开发者开发一个Java模块&#xff08;不管是Jar包还是Apk&#xff09;时&#xff1a; 在PC平台上&#xff0c;该模块包含的每一个Java源码文件都会对应生成一个同文件…

蝴蝶Butterfly 数据集VOC+yolo-2000张(labelImg标注)

蝴蝶被誉为“会飞的花朵”&#xff0c;是一类非常美丽的昆虫。蝴蝶大多数体型属于中型至大型&#xff0c;翅展在15~260毫米之间&#xff0c;有2对膜质的翅。体躯长圆柱形&#xff0c;分为头、胸、腹三部分。体及翅膜上覆有鳞片及毛&#xff0c;形成各种色彩斑纹。今天要介绍的是…

Mistral AI 推出高质量的稀疏专家混合AI人工智能模型——SMoE,有望超越ChatGPT3.5

Mistral AI&#xff08;“Mistral AI”是一家由前DeepMind和Meta Platforms&#xff08;META.US&#xff09;的研究人员组建的新公司。&#xff09;继续履行为开发者社区提供最佳开放模型的使命。他们发布了 Mixtral 8x7B&#xff0c;这是一个高质量的稀疏专家混合模型&#xf…

YOLOv8改进 | 2023主干篇 | 替换LSKNet遥感目标检测主干 (附代码+修改教程+结构讲解)

一、本文介绍 本文给大家带来的改进内容是LSKNet&#xff08;Large Kernel Selection, LK Selection&#xff09;&#xff0c;其是一种专为遥感目标检测设计的网络架构&#xff0c;其核心思想是动态调整其大的空间感受野&#xff0c;以更好地捕捉遥感场景中不同对象的范围上下…

【精选】SpringMVC简介及其执行流程,参数获取方式

SpringMVC简介 MVC模型 MVC全称Model View Controller&#xff0c;是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分&#xff1a; Model&#xff08;模型&#xff09;&#xff1a;指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中&…

37.分支结构嵌套

目录 一.什么是分支结构嵌套 二.什么情况下会用分支结构嵌套 三.举例 四.注意事项 五.视频教程 一.什么是分支结构嵌套 在一个if语句中又包含了另外一个if语句&#xff0c;这种情况称之为if语句的嵌套&#xff0c;也叫做分支结构嵌套。 二.什么情况下会用分支结构嵌套 如…

dToF直方图之美_激光雷达多目标检测

直方图提供了一种简单有效的方法来分析信号分布并识别与目标存在相对应的峰值,并且能够可视化大量数据,让测距数形结合。在车载激光雷达中,对于多目标检测,多峰算法统计等,有着区别于摄像头以及其他雷达方案的天然优势。 如下图,当中有着清晰可见的三个峰值,我们可以非…