Qt项目网络聊天室设计

news2024/9/21 2:37:51

效果演示

网络聊天室

Qt网络聊天室服务端

网络聊天室程序

  1. 基于TCP的可靠连接(QTcpServer、QTcpSocket)

  2. 一个服务器,多个客户端

  3. 服务器接收到某个客户端的请求以及发送信息,经服务器发给其它客户端 最终实现一个共享聊天内容的聊天室!

QTcpServer

提供一个TCP基础服务类 继承自QObject,这个类用来接收到来的TCP连接,可以指定TCP端口或者用QTcpServer自己挑选一个端口,可以监听一个指定的地址或者所有的机器地址。

QTcpServer的信号:

newConnection()//有新连接连接时触发该信号

配置

pro文件添加

QT += network

获取当前设备所有ip地址

枚举设备所有ip地址

QList<QHostAddress> ipList = QNetworkInterface::allAddresses();
QStringList addressStrList;
addressStrList.clear();

for(int index = 0;index<ipList.size();index++)
{
    if(ipList.at(index).isNull())   continue;         //如果地址为空,则去掉
    QAbstractSocket::NetworkLayerProtocol protocol = ipList.at(index).protocol();
    if(protocol != QAbstractSocket::IPv4Protocol)   continue;           //只取IPV4的地址
    addressStrList.append(ipList.at(index).toString());
}
ui->comboBox_Address->addItems(addressStrList);

listen() close()

调用listen()来监听所有的连接 调用close()来关闭套接字,停止对连接的监听。

如果监听有错误,serverError()返回错误的类型。调用errorString()来把错误打印出来

bool isListening()	const

当服务端正在监听连接时候返回真,否则返回假

QString serverAddressStr = ui->comboBox_Address->currentText();     //获取服务器ip地址
quint16 port = ui->lineEdit_port->text().toInt();                   //获取服务器端口
QHostAddress serverAddress = QHostAddress(serverAddressStr);        //初始化协议族

if(mServer->isListening())
{
    //在监听状态 取消监听
    mServer->close();
}
else
{
    //不在监听状态 开始监听
    if(mServer->listen(serverAddress, port))
    {
        //监听成功
        qDebug() << "Listen Ok!!";
    }
    else
    {
        //监听失败
        QMessageBox::warning(this, "Tcp Server Listen Error", mServer->errorString());
    }
}

当监听连接时候,可以调用serverAddress()serverPort()来返回服务端的地址和端口。

newConnection()

每当一个newConnection新的客户端连接到服务端就会发射信号newConnection()

调用nextPendingConnection()来接受待处理的连接。返回一个连接的QTcpSocket(),我们可以用这个返回的套接字和客户端进行连接

private slots:
    void newConnectionSlot();           //新连接
//处理新连接客户端
connect(mServer, SIGNAL(newConnection()),this, SLOT(newConnectionSlot()));
void Widget::newConnectionSlot()
{
    mClient = mServer->nextPendingConnection();
    connect(mClient, SIGNAL(readyRead()),this, SLOT(readyReadSlot()));//接收消息
    connect(mClient, SIGNAL(disconnected()),this, SLOT(disconnectedSlot()));//断开连接
}

SINGL

readyRead()

客户端有数据发送至服务端时触发该信号

connect(mClient, SIGNAL(readyRead()),this, SLOT(readyReadSlot()));          //接收消息

isReadable

是否可读

readAll

读取客户端发送过来的全部信息

if(mClient->isReadable())
{
	QByteArray recvArray = mClient->readAll();
}

disconnected()

当客户端断开连接时触发该信号

connect(mClient, SIGNAL(disconnected()),this, SLOT(disconnectedSlot()));    //断开连接

UI设计

服务端UI设计

TcpServer项目训练

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QNetworkInterface>
#include <QAbstractSocket>
#include <QTcpServer>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDateTime>

namespace Ui {
class Widget;
}

class Widget :public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_pushButton_listen_clicked();//开始监听
    void newConnectionSlot();           //新连接
    void disconnectedSlot();            //断开连接
    void readyReadSlot();               //接收消息的槽函数
    void on_pushButton_send_clicked();	//发送消息

private:
    void enumIpAddress();				//枚举当前设备所有端口
private:
    Ui::Widget *ui;

    QTcpServer *mServer;				//服务器
    QTcpSocket *mClient = nullptr;		//客户端
    QList<QTcpSocket *>mClientList;		//客户端链表
};

#endif // WIDGET_H

widget.cpp

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

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

    //处理新连接客户端
    connect(mServer, SIGNAL(newConnection()),this, SLOT(newConnectionSlot()));
}

Widget::~Widget()
{
    delete ui;
}
void Widget::enumIpAddress()
{
    QList<QHostAddress> ipList = QNetworkInterface::allAddresses();
    QStringList addressStrList;
    addressStrList.clear();

    for(int index = 0;index<ipList.size();index++)
    {
        if(ipList.at(index).isNull())   continue;         //如果地址为空,则去掉
        QAbstractSocket::NetworkLayerProtocol protocol = ipList.at(index).protocol();
        if(protocol != QAbstractSocket::IPv4Protocol)   continue;           //只取IPV4的地址
        addressStrList.append(ipList.at(index).toString());
    }
    ui->comboBox_Address->addItems(addressStrList);
}

void Widget::on_pushButton_listen_clicked()
{
    QString serverAddressStr = ui->comboBox_Address->currentText();     //获取服务器ip地址
    quint16 port = ui->lineEdit_port->text().toInt();                   //获取服务器端口
    QHostAddress serverAddress = QHostAddress(serverAddressStr);        //初始化协议族

    if(mServer->isListening())
    {
        //在监听状态 取消监听
        mServer->close();
        ui->pushButton_listen->setText("监听");
    }
    else
    {
        //不在监听状态 开始监听
        if(mServer->listen(serverAddress, port))
        {
            //监听成功
            qDebug() << "Listen Ok!!";
            ui->pushButton_listen->setText("停止监听");
        }
        else
        {
            //监听失败
            QMessageBox::warning(this, "Tcp Server Listen Error", mServer->errorString());
        }
    }
}

void Widget::newConnectionSlot()
{
    QString clientInfo;

    mClient = mServer->nextPendingConnection();
    mClientList.append(mClient);
    //窥视Client 信息
    clientInfo = mClient->peerAddress().toString() + ":"+  QString::number(mClient->peerPort());
    ui->listWidget_client->addItem(clientInfo);

    connect(mClient, SIGNAL(readyRead()),this, SLOT(readyReadSlot()));          //接收消息

    connect(mClient, SIGNAL(disconnected()),this, SLOT(disconnectedSlot()));    //断开连接
}

void Widget::readyReadSlot()
{
    QByteArray recvArray;
    QTcpSocket* current = nullptr;
    if(!mClientList.isEmpty())
    {
        //接收客户端数据
        for(int index = 0;index < mClientList.count();index ++)
        {
            current = mClientList.at(index);

            if(current->isReadable())
            {
                recvArray = current->readAll();
                if(recvArray.isEmpty()) continue;
                QString str = QString(QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss ddd")) +
                        ":Recv\n" + str.fromLocal8Bit(recvArray.data());    //本地GBK转Unicode 解决乱码
                ui->textBrowser_recv->append(str);
                break;
            }
        }
        //转发给其他客户端
        for(int index = 0;index < mClientList.count();index ++)
        {
            QTcpSocket* temp = mClientList.at(index);
            if(current == temp) continue;
            if(temp->isWritable())
            {
                temp->write(recvArray);
            }
        }
    }
}

void Widget::disconnectedSlot()
{
    QMessageBox::information(this, "client close Signal", "client over");
}

void Widget::on_pushButton_send_clicked()
{
    QString sendString = ui->plainTextEdit_send->toPlainText();
    QByteArray sendArr = sendString.toLocal8Bit();

    //群发给所有客户端连接
    if(!mClientList.isEmpty())
    {
        for(int index = 0;index < mClientList.count();index ++)
        {
            QTcpSocket* temp = mClientList.at(index);
            if(temp->isWritable())
            {
                temp->write(sendArr);
            }
        }
    }
    QString str = QString(QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss ddd"))
            + ":Send\n" + sendString;
    ui->textBrowser_recv->append(str);          //本地GBK转Unicode 解决乱码
}

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

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

相关文章

大数据治理.数据采集/归集技术

第一部分 阿里巴巴DATAx DataX 是阿里开源的一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 DataX设计理念 DataX本身作为数据同步框架&#xff0c;将不同…

分布式系统消息通信技术:MOM与RPC

一、中间件 什么是中间件 中间件&#xff08;Middleware&#xff09;是处于操作系统和应用程序之间的软件&#xff0c;也有人认为它应该属于操作系统中的一部分。人们在使用中间件时&#xff0c;往往是一组中间件集成在一起&#xff0c;构成一个平台&#xff08;包括开发平台…

springboot配置 spring.profiles.active spring.profiles.include @profile

springboot配置 spring.profiles.active spring.profiles.include profile spring.profiles.active spring.profiles.include profile的命名方式 以 application-开头, --横杠(减号)不能少 application-{这部分自定义}.propertiesapplication-{这部分自定义}.ymlapplicatio…

c++多态详解

前言&#xff1a; 对于面向对象语言来说&#xff0c;多态是面向对象的三大特性之一&#xff0c;简单一点来说多态就是多种形态&#xff0c;是不同对象接收到同一种消息产生的不同动作或者反应&#xff0c;听起来有点抽象&#xff0c;实际上就是完成一个任务让不同的对象来做产生…

合宙Air724UG Cat.1模块硬件设计指南--模拟语音通道

模拟语音通道 简介 模拟音频技术是由传感器采集得到的连续变化的值&#xff0c;根据其电压的幅度用来展示声音强弱。CAT.1内置3种音频输出模式&#xff0c;分别为扬声器(SPK)输出&#xff0c;耳机(HP)输出和听筒(RECEIVER)输出。 特性 SPK接口 SPK-、SPK。Speaker差分信号接口…

记压测环境数据表死锁导致接口长时间pending问题

背景 压测过程中测试小伙伴反映某个页面长时间loading无法打开&#xff0c;接下来我们排查一下&#xff0c;既然是压测环境&#xff0c;那么就需要排除服务器资源层面的因素&#xff0c;现在考验的就是在系统资源不足时系统的情况&#xff0c;那么我们就直接从代码层面开始排查…

PADS-LAYOUT菜单及工具说明

目录 1 材料清单输出 2 元件属性检查 3 材料清单制作 4 原理图生成PDF 4.1PDF文件生成 4.2PDF文件查阅 4.3PDF文件打印 5 PADS转Altium Designer 5 Altium Designer转PADS 5.1 直接导入法 5.2 软件生成法 6 PADS层定义 7 设计规则输出 7.1 PADS对象管理 7.2 PAD…

pandas---分箱(离散化处理)、绘图、交叉表和透视表

1. 分箱 分箱操作就是将连续型数据离散化。分箱操作分为等距分箱和等频分箱. 1.1 等宽分箱 pandas.cut(x, bins, rightTrue, labelsNone, retbinsFalse, precision3, include_lowestFalse, duplicatesraise, orderedTrue) x&#xff1a;要分箱的一维数组或者 Series。 bi…

分布式系统概念和设计——分布式共享内存

分布式系统概念和设计 分布式共享内存 分布式共享内存是在不共享物理内存的计算机之间实现数据的共享的一个抽象。 有一个底层运行的系统保证其透明性&#xff0c;但是进程还是根据内存的分布处理物理内存的分布式能力 DMS最关键点&#xff1a; 不需要关心数据的通信&#xff…

百家号热议排名代发

百家号热议排名代发&#xff0c;百度排名怎么做&#xff0c;有什么技巧或者方式方法吗#百度首页关键词排名#百度推广#百度竞价推广#百度关键词排名#百度首页关键词排名方法# 其实百度推广并不赚钱&#xff0c;也没有你想象中的那么好做。 我说三点&#xff0c; 99% 的用户都遇…

C语言之动态内存分配讲解(2)

动态内存函数的介绍 在开始本章节之前&#xff0c;我们来复习一下动态内存分配&#xff08;1&#xff09;中所讲到的知识&#xff0c;看下面目录一和目录二 为什么存在动态内存分配 我们已经掌握的内存开辟方式有 int val 20;//在栈空间上开辟四个字节 char arr[10] {0};/…

Go语言并发之扇入和扇出

1、Go语言并发之扇入和扇出 编程中经常遇到扇入和扇出两个概念&#xff0c;所谓的扇入是指将多路通道聚合到一条通道中处理&#xff0c;Go 语言最简单的扇入 就是使用 select 聚合多条通道服务&#xff1b;所谓的扇出是指将一条通道发散到多条通道中处理&#xff0c;在Go语言…

揭开视频识别(动作识别)的神秘面纱(附代码和demo)!

PaddleDetection 在计算机视觉中&#xff0c;视频识别和检测是一个重要的方向。历年来CVPR和ICCV等顶会文章中这类论文是最多的。视频识别和检测也是最有落地场景前景的&#xff0c;像人脸识别、动作检测、异常检测、行人重识别、行人计数等都是很有落地前景的应用方向。本文介…

shardingsphere第三课各种功能点及核心源码

一、功能点 1.审计功能 分片审计功能是针对数据库分片场景下对执行的 SQL 语句进行审计操作。分片审计既可以进行拦截操作&#xff0c;拦截系统配置的非法 SQL 语句&#xff0c;也可以是对 SQL 语句进行统计操作。 目前ShardingSphere内置的分片审计算法只有一个&#xff0c;…

C语言指针初进阶知识汇总

目录 1 指针 1.1 指针是乜嘢 1.2 指针的声明 1.3 运算符 1.4 简单的小例子们 1.5 指针的运算 1.5.1 指针加减运算 1.5.2 间址运算 1.5.3 指针的相减 两个地址之间的偏移量 2 指针与数组 2.1 指针和一维数组 2.1.1 定义数组及指针变量 2.1.2 能动手就不要瞎扯 2.…

当 Rokid 遇上函数计算

作者&#xff1a;王彬&#xff08;阿里云解决方案架构师&#xff09;、姚兰天&#xff08;Rokid 技术专家&#xff09;、聂大鹏&#xff08;阿里云高级技术专家 &#xff09; 公司背景和业务 Rokid 创立于2014年&#xff0c;是一家专注于人机交互技术的产品平台公司。Rokid 通…

2023/6/18周报

目录 摘要 论文阅读 1、题目和现有问题 2、工作流程 3、图神经网络模块 4、注意力网络 5、实验结果和分析 深度学习 1、GNN和GRU的融合 2、相关公式推导 总结 摘要 本周在论文阅读上&#xff0c;对基于图神经网络和改进自注意网络的会话推荐的论文进行了学习&#…

DPdisPCA算法原理笔记

概要 本文简单理顺《Differentially Private Distributed Principal Component Analysis》论文中的算法原理&#xff0c;它主要提出了一种基于差分隐私的分布式PCA算法&#xff0c;研究了该算法在实验数据以及真实数据中的表现&#xff0c;在参数相同的情况下本算法取得了和没…

OpenGL之深度测试

文章目录 深度测试深度测试函数源代码 深度测试 深度缓冲就像颜色缓冲(Color Buffer)&#xff08;储存所有的片段颜色&#xff1a;视觉输出&#xff09;一样&#xff0c;在每个片段中储存了信息&#xff0c;并且&#xff08;通常&#xff09;和颜色缓冲有着一样的宽度和高度。深…

Python3 条件控制与循环语句 | 菜鸟教程(八)

目录 一、Python3 条件控制 &#xff08;一&#xff09;Python 条件语句是通过一条或多条语句的执行结果&#xff08;True 或者 False&#xff09;来决定执行的代码块。 &#xff08;二&#xff09;if 语句 1、Python中if语句的一般形式如下所示&#xff1a; 2、注意&#…