QTday05(TCP的服务端客户端通信)
实现聊天室功能
服务端代码:
pro文件需要导入 network
头文件:
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>//服务端
#include <QTcpSocket>//客户端
#include <QList>
#include <QMessageBox>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_startBtn_clicked();
public slots:void newConnectSlot();//建立连接的槽函数void readyReadSlot();//接收消息的槽函数private:Ui::Widget *ui;//实例化服务器对象QTcpServer *server;//创建存放客户端信息的容器QList<QTcpSocket *> socketList;
};
#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);//实例化服务器对象server=new QTcpServer(this);}Widget::~Widget()
{delete ui;
}void Widget::on_startBtn_clicked()
{//监听任意ip的指定端口bool listen_res=server->listen(QHostAddress::Any,ui->portLine->text().toUInt());if(listen_res){//监听成功QMessageBox::information(this,"提示","设置监听成功",QMessageBox::Ok);}else{//监听失败QMessageBox::information(this,"提示","设置监听失败",QMessageBox::Ok);return;}//等待连接connect(server,&QTcpServer::newConnection,this,&Widget::newConnectSlot);
}void Widget::newConnectSlot()
{//接收到newConnect信号之后的槽函数,处理接下来的操作//获取客户端的套接字,加入容器QTcpSocket *s=server->nextPendingConnection();socketList.push_back(s);qDebug() << "有新客户连接" << s->peerName() << ";" << s->peerAddress().toString() << ":" << QString::number(s->peerPort()) <<endl;//此时如果客户端向服务器发送数据,客户端会发送一个readyRead信号connect(s,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);
}void Widget::readyReadSlot()
{//客户端有数据发送,触发改槽函数//遍历容器,移除无效客户端,接收有效客户端消息for (int i=0;i<socketList.count();i++) {//如果是非链接状态就移除if(socketList.at(i)->state()==QAbstractSocket::UnconnectedState){socketList.removeAt(i);}}for (int i=0;i<socketList.count();i++) {//如果有字节,就读取并放到ui界面if(socketList.at(i)->bytesAvailable()){QByteArray msg=socketList.at(i)->readAll();QString msgInfo=socketList.at(i)->peerAddress().toString()+":"+QString::number(socketList.at(i)->peerPort())+":"+QString::fromLocal8Bit(msg);ui->listWidget->addItem(msgInfo);for (int j=0;j<socketList.count();j++) {socketList.at(j)->write(msg);}}}
}
ui:

客户端代码:
头文件
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QtDebug>
#include <QMessageBox>
#include <QTcpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_connnectBtn_clicked();void on_disconnectBtn_clicked();void on_sendBtn_clicked();public slots:void connnectedSlot();void readyReadSlot();void disconnectedSlot();private:Ui::Widget *ui;//实例化客户端QTcpSocket *socket;//定义全局变量存储用户名QString username;
};
#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);//实例化客户端socket=new QTcpSocket(this);//将发送和断开连接 的按钮默认设置不可用ui->sendBtn->setDisabled(true);ui->disconnectBtn->setDisabled(true);ui->accoutLine->setText("张三");ui->ipLine->setText("192.168.125.77");ui->portLine->setText("8888");//连接成功会触发connected信号,只需要一次connect(socket,&QTcpSocket::connected,this,&Widget::connnectedSlot);//收信号connect(socket,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnectedSlot);
}Widget::~Widget()
{delete ui;
}void Widget::on_connnectBtn_clicked()
{//连接服务器username=ui->accoutLine->text();QString ip=ui->ipLine->text();quint16 port=ui->portLine->text().toUInt();socket->connectToHost(ip,port);//判断是否连接成功:连接成功后,户端会自动发射一个connected信号,}void Widget::connnectedSlot()
{QMessageBox::information(this,"提示","连接成功");QString msg=username+"进入聊天室";socket->write(msg.toLocal8Bit());ui->sendBtn->setDisabled(false);ui->connnectBtn->setDisabled(true);ui->disconnectBtn->setDisabled(false);}void Widget::on_disconnectBtn_clicked()
{QString msg=username+"离开聊天室";socket->write(msg.toLocal8Bit());socket->disconnectFromHost();}void Widget::on_sendBtn_clicked()
{if(ui->infoLine->text().isEmpty()){QMessageBox::information(this,"提示","发送的消息不能为空");return;}QString msg=ui->infoLine->text();socket->write(msg.toLocal8Bit());ui->infoLine->setText("");
}
void Widget::readyReadSlot(){QByteArray msg=socket->readAll();ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}void Widget::disconnectedSlot()
{ui->sendBtn->setDisabled(true);ui->disconnectBtn->setDisabled(true);ui->connnectBtn->setDisabled(false);QMessageBox::information(this,"提示","断开连接成功");
}
ui:

运行结果:客户端连接之后可以成功发送信息

今日思维导图:

将聊天功能加入到仿qq登录之后:

代码:
page2.h:
#ifndef PAGE2_H
#define PAGE2_H#include <QWidget>
#include <QMovie>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDebug>
#define PORT 8888
#define IP "192.168.125.77"namespace Ui {
class Page2;
}class Page2 : public QWidget
{Q_OBJECTpublic:explicit Page2(QWidget *parent = nullptr);~Page2();
public slots:void login_slot();void connectedSlot();void readyReadSlot();
private slots:void on_sendBtn_clicked();private:Ui::Page2 *ui;QTcpSocket *socket;};#endif // PAGE2_H
widget.h:
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QMovie>
#include <QMessageBox>
#include <QDebug>
#include <QMouseEvent>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;public slots:void loginButton_slot();signals:void login_signal();private:Ui::Widget *ui;QPoint p;//定义全局变量p,记录位置
public:static QString username;
};#endif // WIDGET_H
main.cpp:
#include "widget.h"
#include "page2.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();Page2 p2;QObject::connect(&w,&Widget::login_signal,&p2,&Page2::login_slot);return a.exec();
}
page2.cpp:
#include "page2.h"
#include "widget.h"
#include "ui_page2.h"Page2::Page2(QWidget *parent) :QWidget(parent),ui(new Ui::Page2)
{ui->setupUi(this);QMovie *movie = new QMovie(":/111/cai.gif");ui->label->setMovie(movie);ui->label->setScaledContents(true);movie->start();//实例化客户端socket=new QTcpSocket(this);qDebug() << "实例化客户端";//建立connected信号和指定槽函数的连接connect(socket,&QTcpSocket::connected,this,&Page2::connectedSlot);//建立readyRead信号和指定槽函数连接connect(socket,&QTcpSocket::readyRead,this,&Page2::readyReadSlot);}Page2::~Page2()
{delete ui;
}void Page2::login_slot()
{qDebug() << "登录按钮";this->show();//连接客户端socket->connectToHost(IP,PORT);
}void Page2::connectedSlot()
{//连接成功后触发该槽函数qDebug() << "连接成功";QMessageBox::information(this,"提示","连接成功");QString msg=Widget::username+"加入了聊天";socket->write(msg.toLocal8Bit());
}void Page2::readyReadSlot()
{//收到服务端发送的消息时触发该槽函数QByteArray msg=socket->readAll();ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}void Page2::on_sendBtn_clicked()
{if(ui->infoEdit->toPlainText().isEmpty()){QMessageBox::information(this,"提示","发送的消息不能为空");return;}QString msg=ui->infoEdit->toPlainText();socket->write(msg.toLocal8Bit());ui->infoEdit->clear();
}
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
QString Widget::username="";
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setFixedSize(560,430);this->setStyleSheet("background-color:#faf7ec");this->setWindowFlag(Qt::FramelessWindowHint);//无边框QMovie *movie = new QMovie(":/111/cai.gif");ui->backLabel->setMovie(movie);ui->backLabel->setScaledContents(true);movie->start();ui->closeButton->setStyleSheet("border-image:url(:/111/basketball.png)");ui->avatorLabel->resize(60,60);ui->avatorLabel->setStyleSheet("border-image:url(:/111/user.png);border-radius:30px");ui->accountLabel->setPixmap(QPixmap(":/111/account.jpg"));//ui->accountLabel->resize(40,40);ui->accountLabel->setScaledContents(true);ui->passwdLabel->setPixmap(QPixmap(":/111/passwd.jpg"));//ui->passwdLabel->resize(40,40);ui->passwdLabel->setScaledContents(true);ui->accoountLine->setPlaceholderText("账号");ui->passwdLine->setPlaceholderText("密码");ui->passwdLine->setEchoMode(QLineEdit::Password);ui->loginLabel->setPixmap(QPixmap(":/111/2.png"));ui->loginLabel->setScaledContents(true);ui->loginButton->setStyleSheet("background-color:#409EFF;border-radius:5px");connect(ui->closeButton,SIGNAL(clicked()),this,SLOT(close()));connect(ui->loginButton,&QPushButton::clicked,this,&Widget::loginButton_slot);}Widget::~Widget()
{delete ui;
}void Widget::loginButton_slot()
{//判断用户账号密码的正确性if(ui->accoountLine->text()=="admin"&&ui->passwdLine->text()=="123456"){username="admin";qDebug() << "登录成功" <<endl;QMessageBox::information(this,"提示","登录成功",QMessageBox::Ok);this->close();//开启新窗口,手动触发信号emit login_signal();}else{qDebug() << "账号或者密码错误" <<endl;int res=QMessageBox::information(this,"提示","账号或者密码错误,是否继续登录",QMessageBox::Ok|QMessageBox::No);if(res==QMessageBox::Ok){ui->passwdLine->setText("");}else{this->close();}}
}
void Widget::mousePressEvent(QMouseEvent *event){p=event->pos();
}
void Widget::mouseMoveEvent(QMouseEvent *event){if(event->buttons()==Qt::LeftButton)this->move(event->globalPos()-p);
}
page2.ui:

widget.ui:

运行结果:

相关文章:
QTday05(TCP的服务端客户端通信)
实现聊天室功能 服务端代码: pro文件需要导入 network 头文件: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer>//服务端 #include <QTcpSocket>//客户端 #include <QList> #include <QMes…...
【MATLAB源码-第52期】基于matlab的4用户DS-CDMA误码率仿真,对比不同信道以及不同扩频码。
操作环境: MATLAB 2022a 1、算法描述 1. DS-CDMA系统 DS-CDMA (Direct Sequence Code Division Multiple Access) 是一种多址接入技术,其基本思想是使用伪随机码序列来调制发送信号。DS-CDMA的特点是所有用户在同一频率上同时发送和接收信息…...
Spring 路径与占位符
SpringMVC支持ant风格的路径 ?:表示任意的单个字符 *:表示任意的0个或多个字符 \**:表示任意的一层或多层目录 注意:在使用**时,只能使用/**/xxx的方式 1.测试 ? <a th:href"{/succe…...
MIT 6.824 -- Cache Consistency -- 11
MIT 6.824 -- Cache Consistency -- 11 引言严峻挑战锁服务缓存一致性问题案例演示优化 原子性问题故障恢复问题log内容故障恢复 小结 课程b站视频地址: MIT 6.824 Distributed Systems Spring 2020 分布式系统 推荐伴读读物: 极客时间 – 大数据经典论文解读DDIA – 数据密集…...
Python在列表中如何对多个参数进行修改
1 问题 在python中经常会使用到列表,列表是常见的一种数据类型。对于一个庞大的列表,要调取列表中的对象,应如何快速准确的调取或快速的调取多个对象? 2 方法 解决问题的步骤采用如下方式: 基本的,已知元素…...
手机启用adb无线调试
具体步骤 手机和电脑处于同一个路由器下。 比如手机IP是192.168.31.181,电脑能ping通。 手机端启用无线adb调试先把手机用USB线连接电脑,打开adb,输入以下命令: G:\> adb tcpip 5555 restarting in TCP mode port: 5555 无…...
openGauss学习笔记-105 openGauss 数据库管理-管理用户及权限-默认权限机制
文章目录 openGauss学习笔记-105 openGauss 数据库管理-管理用户及权限-默认权限机制 openGauss学习笔记-105 openGauss 数据库管理-管理用户及权限-默认权限机制 数据库对象创建后,进行对象创建的用户就是该对象的所有者。openGauss安装后的默认情况下,…...
[翻译]理解Postgres的IOPS:为什么数据即使都在内存,IOPS也非常重要
理解Postgres的IOPS:为什么数据即使都在内存,IOPS也非常重要 磁盘IOPS(每秒输入/输出操作数)是衡量磁盘系统性能的关键指标。代表每秒可以执行的读写操作数量。对于严重依赖于磁盘访问的PG来说,了解和优化磁盘IOPS对实…...
Day6力扣打卡
打卡记录 统计无向图中无法互相到达点对数(并查集 / DFS) 链接 并查集 思路:用并查集将连通区域的连在一起,再遍历所有点,用hash表存储不同连通块的元素个数,然后 乘积和 便是答案。 注意: /…...
10月面试js基础
作用域 变量的可用范围 作用域链 保存的变量的使用顺序的一个链(也就是路线图), 被称为作用域链。 当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再…...
研发日常踩坑-Mysql分页数据重复 | 京东云技术团队
踩坑描述: 写分页查询接口,order by和limit混用的时候,出现了排序的混乱情况 在进行第N页查询时,出现与第一前面页码的数据一样的记录。 问题 在MySQL中分页查询,我们经常会用limit,如:limit(0,20)表示查询第一页的…...
Ubuntu18.04安装QGC报错 `GLIBC_2.29‘ not found
按照官网教程,最后运行时出错。 /tmp/.mount_QGroun2NOhPP/QGroundControl: /lib/x86_64-linux-gnu/libm.so.6: version GLIBC_2.29 not found (required by /tmp/.mount_QGroun2NOhPP/QGroundControl) /tmp/.mount_QGroun2NOhPP/QGroundControl: /usr/lib/x86_64-…...
回归预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元多输入单输出回归预测
回归预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元多输入单输出回归预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-GRU贝叶斯优化门控循环单元回归预测。基于贝…...
Easyx趣味编程7,鼠标消息读取及音频播放
hello大家好,这里是dark flame master,今天给大家带来Easyx图形库最后一节功能实现的介绍,前边介绍了绘制各种图形及键盘交互,文字,图片等操作,今天就可以使写出的程序更加生动且容易操控。一起学习吧&…...
towxml的使用,在微信小程序中快速将markdown格式渲染为wxml文本
towxml的使用,在微信小程序中快速将markdown格式渲染为wxml文本 Towxml概述安装下载 Towxml在小程序中使用 towxml Towxml概述 towxml3.0 支持以下功能: ● echarts图表,默认禁用,需自行构建以开启此功能 ● LaTeX数学公式&#…...
项目管理实战总结(一)-沟通路径问题
前言 那是2021年春节之后,我决定主动申请参与到这个项目,是知道工作强度大、难度大的情况的。有很多的同事是想躲,而我是明知山有虎偏向虎山行。我确定,通过这个项目,一定有我需要的东西。现在项目已经完成了终验专家…...
UE5场景逐渐变亮问题
1、显示 -- 关闭眼部适应 2、项目设置 -- 关闭自动曝光 参考: 虚幻5/UE5 场景亮度逐渐变亮完美解决方法 - 哔哩哔哩...
VM16Pro的Win10虚拟机安装Linux子系统Kali
VM16Pro的Win10虚拟机安装Linux子系统Kali 一、启用Windows功能二、配置WSL三、安装Kali四、安装kali基本工具包五、图形化六、适用的报错七、其他问题参考 一、启用Windows功能 启用后需重启二、配置WSL wsl --update #管理员启动Powershell执行,完成后将下面…...
C++中类的声明
C中类的声明 假设您要编写一个模拟人(如您自己)的程序。人有其特征:姓名、出生日期、出生地和性别(这些信息让每个人都是独一无二的),还能做某些事情,如交谈、自我介绍等。 要在程序中模拟人&…...
IDEA常用AI插件
只推荐免费的 一、对话式AI 1. ChatGPT GPT-4 - Bito AI Code Assistant ChatGPT GPT-4 - Bito AI Code Assistant 插件地址:https://plugins.jetbrains.com/plugin/18289-chatgpt-gpt-4–bito-ai-code-assistant支持自定义prompt支持解释代码支持生成代码注释支持…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
手动给中文分词和 直接用神经网络RNN做有什么区别
手动分词和基于神经网络(如 RNN)的自动分词在原理、实现方式和效果上有显著差异,以下是核心对比: 1. 实现原理对比 对比维度手动分词(规则 / 词典驱动)神经网络 RNN 分词(数据驱动)…...
NineData数据库DevOps功能全面支持百度智能云向量数据库 VectorDB,助力企业 AI 应用高效落地
NineData 的数据库 DevOps 解决方案已完成对百度智能云向量数据库 VectorDB 的全链路适配,成为国内首批提供 VectorDB 原生操作能力的服务商。此次合作聚焦 AI 开发核心场景,通过标准化 SQL 工作台与细粒度权限管控两大能力,助力企业安全高效…...
使用python进行图像处理—图像变换(6)
图像变换是指改变图像的几何形状或空间位置的操作。常见的几何变换包括平移、旋转、缩放、剪切(shear)以及更复杂的仿射变换和透视变换。这些变换在图像配准、图像校正、创建特效等场景中非常有用。 6.1仿射变换(Affine Transformation) 仿射变换是一种…...
跨域请求解决方案全解析
跨域请求可以通过多种技术方案实现,核心是绕过浏览器的同源策略限制。以下是主流解决方案及具体实现方式: 一、CORS(跨域资源共享) 最常用的标准化方案,通过服务器设置HTTP响应头实现: Access-Control-Al…...
1.springmvc基础入门(一)
1.Spring MVC概念 Spring MVC 是 Spring Framework 提供的 Web 组件,全称是 Spring Web MVC,是⽬前主流的实现 MVC 设计模式的框架,提供前端路由映射、视图解析等功能。 Java Web 开发者必须要掌握的技术框架。 2.Spring MVC 功能 MVC&am…...
前端对WebSocket进行封装,并建立心跳监测
WebSocket的介绍: WebSocket 是一种在客户端和服务器之间进行全双工、双向通信的协议。它是基于 HTTP 协议,但通过升级(HTTP 升级请求)将连接转换为 WebSocket 协议,从而提供更高效的实时数据交换。 WebSocket 的特点…...
