当前位置: 首页 > news >正文

【QT开发(14)】QT P2P chat 聊天

在【P2P学习(2)】P2P 通信,主要存在四种不同的网络模型的第一阶段:集中式P2P 模式

最简单的路由方式就是集中式,即存在一个中心节点保存了其他所有节点的索引信息,索引信息一般包括节点 IP 地址、端口、节点资源等。集中式路由的优点就是结构简单、实现容易。但缺点也很明显,由于中心节点需要存储所有节点的路由信息,当节点规模扩展时,就很容易出现性能瓶颈;而且也存在单点故障问题。

一般是有一个服务器,和一群客户端。各个客户端可以两两相互发送消息。各个客户端用IP地址和TCP/IP监听端口号进行标识。客户端,可执行注册和聊天过程;注册服务器,主要用于注册客户端和分发注册客户端信息。

技术点:

  • GUI
  • 多线程
  • 套接字编程

1 QT 项目引入库cmake

认识Qt5::Network
Qt中提供的所有的Socket类都是非阻塞的。

QTcpSocket 用于TCP/IP通信,作为客户端套接字使用。
QTcpServer 用于TCP/IP通信,作为服务器端套接字使用。
QUdpSocket 用于UDP通信,服务器,客户端均使用此套接字。

文档资料:

官方文档: Qt Network C++ Classes:https://doc.qt.io/qt-5/qtnetwork-module.html
C++ QTcpSocket::waitForConnected方法代码示例:https://vimsky.com/examples/detail/cpp-ex—QTcpSocket-waitForConnected-method.html

CMake下添加,在CMakelists.txt文件中添加以下代码

#设置Qt的支持
set(QT5_LIBRARIESQt5::Network)
#自动查找配置构建工程所需的程序库
find_package(Qt5Network REQUIRED)
#添加可执行文件所需要的库
target_link_libraries(${PROJECT_NAME} ${QT5_LIBRARIES} Qt5::Network)

然后,引入相关类的头文件:

#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>

2 TCP/IP协议

TCP/IP: TCP(Transmission Control Protocol,传输控制协议),IP(Internet Protocol 网络协议)。TCP提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量,是一种流控制。认识TCP可通过以下方面。

  • TCP是一种面向连接的可靠的协议,属于传输层。只有在确认通信对端存在时才会发送数据,从而控制通信流量的浪费。
  • TCP特性: 既保证可靠性,又尽可能的提高性能。
    保证可靠性的机制: 校验和,序列号(按序到达),确认应答,超时重传,连接管理,流量控制,拥塞控制。
    提高性能的机制: 滑动窗口,快速重传,延迟应答,捎带应答。
    定时器: 超时重传定时器,保活定时器,TIME_WAIT定时器。
  • 基于 TCP 的应用层协议: HTTP,HTTPS,SSH,Telnet,FTP,SMTP,基于TCP的自定义的应用层协议。
  • TCP 和 UDP 对比: TCP用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景。UDP用于对高速传输和实时性要求较高的通信领域,例如, 早期的QQ, 视频传输等.;UDP可以用于广播。

2.1 基础:Socket接口

Socket又称"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。

  • TCP/IP提供了封装或者显示数据的具体形式,即可供程序员做网络开发所用的接口。
    socket提供了网络通信的能力,其本质是对TCP/IP的封装的编程接口(API)。
    建立网络通信连接至少要一对Socket端口。
    TCP/IP如果是轿车的话,Socket就是发动机。

2.2 基础:QTcpServer

服务器监听客户端流程

1.创建套接字QTcpServer
2.监听指定的地址和端口号(周期性线程调用)
3.监听是否有Client连接
4.停止监听close
5.通过监听到的QTcpSocket收发数据
6.获取服务器监听状态

创建套接字

QTcpServer* server = new QTcpServer();

监听指定的地址和端口号,即进入Sever启动监听等待Client连接状态

bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);

监听是否有Client连接

QTcpSocket* QTcpServer::nextPendingConnection();

注意,返回的QTcpSocket只能再本线程使用;如果需要在别的线程管理该QTcpSocket,则需要重写QTcpServer::incomingConnection(),将QTcpSocket描述符传递给其他线程并再创建QTcpSocket。

void QTcpServer::incomingConnection(qintptr handle);

停止监听

void QTcpServer::close();

收发数据
根据第3不中返回的QTcpSocket指针,调用read()和write()接口。

其他辅助接口

获取己方和对方的IP和port

quint16 QTcpServer::serverPort() const;
QHostAddress QTcpServer::serverAddress() const;

获取服务器监听状态

bool QTcpServer::isListening() const;

ServerListen 断开重连机制

static int count = 0;
void UserServerlient::Listen() {//1.tcpServer的断开重连if (!tcpClient) { return; }if (isListening() != lastState) {count++;//服务器尝试重新监听某个地址和端口ServerListening();//判断当前服务器监听状态if (isListening()) {std::cout << localIP << "/" << localPort << " 断开重连count: " << count;count = 0;}}//数字10为断开重连次数,根据设置的线程周期时间和实际需求设置if (count >= 10) {lastState = false;delete this;count = 0;return;}//2.检测连接到的Clientif (!child_client) {child_client = server->nextPendingConnection(); //得到每个连进来的socketif (!child_client) {return;}}//检测到Client断开连接,清理内存if (child_client->state() == QAbstractSocket::UnconnectedState) {……}
}    

2.3 基础:QTcpSocket

客户端通信流程

1.创建套接字QTcpSocket
2.连接服务器,使用 QTcpSocket::connectToHost()
3.向服务器发送数据 QTcpSocket::write()
4.接收服务器数据 QTcpSocket::readAll()
5.断开Socket连接等接口
6.获取己方和对方的IP和port,Socket状态等;

创建套接字

QTcpSocket* socket = new QTcpSocket();

客户端连接到服务器端

// ### Qt6: de-virtualize connectToHost(QHostAddress) overload
void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);

连接成功或断开服务器端,或触发connected()和disconnected()信号

Q_SIGNALS:void QAbstractSocket::hostFound();void QAbstractSocket::connected();void QAbstractSocket::disconnected();void QAbstractSocket::stateChanged(QAbstractSocket::SocketState);

连接成功后发送数据。返回值:数据信息的长度。

qint64 QIODevice::write(const char *data, qint64 len);
qint64 QIODevice::write(const char *data);
qint64 QIODevice::write(const QByteArray &data);

连接成功接收数据。返回值:数据信息info

qint64 QIODevice::read(char *data, qint64 maxlen);
QByteArray QIODevice::read(qint64 maxlen);
QByteArray QIODevice::readAll();

当有新的数据到来时,会触发readyRead()信号。因此,要时刻检测数据有数据发送过来,此处应该放在一个循环中,如timer中。

Q_SIGNALS:void QIODevice::readyRead();void QIODevice::aboutToClose();

关闭TCP连接

//会等待数据被写完之后关闭套接字连接
void QAbstractSocket::disconnectFromHost();
//关闭套接字的I/O设备并调用disconnectFromHost()来关闭套接字的连接。
void QIODevice::close() override;     
//调用close(),终止当前连接并重置套接字。与disconnectFromHost()不同,这个函数会立即关闭套接字,丢弃写缓冲区中任何未处理的数据。     
void QAbstractSocket::abort(); 

其他辅助接口

获取己方和对方的IP和port

quint16 QAbstractSocket::localPort() const;
quint16 QAbstractSocket::peerPort() const;
QHostAddress QAbstractSocket::localAddress() const;
QHostAddress QAbstractSocket::peerAddress() const;
QString QAbstractSocket::peerName() const;

获取Socket状态

SocketState QAbstractSocket::state();
enum QAbstractSocket::SocketState {UnconnectedState,   //未连接状态ConnectedState,     //连接状态
};

ClientListen 断开重连机制

static int count = 0;
void UserSocketlient::Listen() {if (!tcpClient) { return; }if (CurrentSocketConnectState() != lastState) {count++;//客服端尝试连接服务器SocketConnecttoSever();//判断当前Socket连接状态if (CurrentSocketConnectState()) {std::cout << localIP << "/" << localPort << " 断开重连count: " << count;count = 0;}}//数字10为断开重连次数,根据设置的线程周期时间和实际需求设置if (count >= 10) {lastState = false;delete this;count = 0;return;}
}

3 开发P2P 的中心服务器

用途:
1、接受客户端的加盟,然后记录客户端的列表信息
2、分发列表信息的端口信息给全体客户端,这样客户端就可相互联系了,不需要中心服务器的支持。
3、实时更新列表,有些下线的,超时的用户踢出去,然后再次广播列表。

3.1 具体流程

参考了adomy/P2PChatRoom;
在这里插入图片描述

4 客户端

在这里插入图片描述

5打包程序

【QT开发(13)】QT发布到其他ubuntu用户

5.1 演示

在这里插入图片描述

仓库

https://gitee.com/hiyanyx/p2-pcha

参考

链接:https://blog.csdn.net/qq_43572400/article/details/128261772

相关文章:

【QT开发(14)】QT P2P chat 聊天

在【P2P学习&#xff08;2&#xff09;】P2P 通信&#xff0c;主要存在四种不同的网络模型的第一阶段&#xff1a;集中式P2P 模式 最简单的路由方式就是集中式&#xff0c;即存在一个中心节点保存了其他所有节点的索引信息&#xff0c;索引信息一般包括节点 IP 地址、端口、节…...

解决adb root命令时错误 adbd cannot run as root in production builds

我测试的手机是小米8&#xff0c;root权限已经刷过了&#xff0c;但是在pc端使用adb root命令的时候&#xff0c;会报错"adbd cannot run as root in production builds" 后来查资料发现是因为Magisk和安卓9版本的问题 https://www.cnblogs.com/jeason1997/p/124105…...

操作系统中套接字和设备独立性软件的关系

网络编程就是编写程序让两台联网的计算机相互交换数据。在我们不需要考虑物理连接的情况下&#xff0c;我们只需要考虑如何编写传输软件。操作系统提供了名为“套接字”&#xff0c;套接字是网络传输传输用的软件设备。 这是对软件设备的解释&#xff1a; 在操作系统中&#…...

C++ Qt/VTK装配体组成联动连接杆

效果 关键代码 #include "View3D.h" #include "Axis.h"#include <vtkActor.h> #include <vtkAppendPolyData.h > #include <vtkAreaPicker.h> #include <vtkAxesActor.h> #include <vtkBox.h> #include <vtkCamera.h>…...

File文件查找

用的是递归调用&#xff0c; &#xff08;递归死循环的结果是导致栈内存溢出错误&#xff09; 一.代码 package org.example;import java.io.File;public class day03 {public static void main(String[] args) {//文件查找&#xff0c;在d&#xff1a;temp下查找改名.mp4sea…...

小程序 wxml2canvas开发文档

wxml: <view class"share__canvas share__canvas1"><view class"share__canvas1-text draw_canvas" data-type"text" data-text"这是一段无边距文字">这是一段无边距文字</view> </view> <canvas canvas-…...

SpringCloud微服务 【实用篇】| 认识微服务

目录 一&#xff1a;认识微服务 1. 微服务框架介绍 2. 服务架构演变 3. 微服务技术对比 4. SpringCloud 图书推荐&#xff1a;《巧用ChatGPT快速提高职场晋升力》 一&#xff1a;认识微服务 本课程学习于黑马&#xff0c;会通过分层次学习&#xff0c;分为三部分去讲解微…...

Csdn文章编写参考案例

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…...

Jmeter性能测试:高并发分布式性能测试

​一、为什么要进行分布式性能测试 当进行高并发性能测试的时候&#xff0c;受限于Jmeter工具本身和电脑硬件的原因&#xff0c;无法满足我们对大并发性能测试的要求。 基于这种场景下&#xff0c;我们就需要采用分布式的方式来实现我们高并发的性能测试要求。 二、分布式性能…...

2015年亚太杯APMCM数学建模大赛B题城市公共交通服务水平动态评价模型求解全过程文档及程序

2015年亚太杯APMCM数学建模大赛 B题 城市公共交通服务水平动态评价模型 原题再现 城市公共交通服务评价是城市公共交通系统建设和提高公共交通运营效率的重要组成部分。对于公交企业&#xff0c;管理和规划部门&#xff0c;传统公交车站、线路和换乘枢纽的规划数据只是基于主…...

CCF CSP认证历年题目自练 Day40

题目 试题编号&#xff1a; 201412-3 试题名称&#xff1a; 集合竞价 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   某股票交易所请你编写一个程序&#xff0c;根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量…...

闲聊一下写技术博客的一些感想

大家好&#xff0c;我是阿赵。   在我的163博客关闭之后&#xff0c;我就把一部分的博文移到了CSDN这边。不过实际上我有好几年都没有写过博客&#xff0c;所以这个博客的浏览量和粉丝数一直都不高。直到今年2023年的2月底开始&#xff0c;打算总结一下3DsMax的MaxScript的用…...

单片机为什么一直用C语言,不用其他编程语言?

单片机为什么一直用C语言&#xff0c;不用其他编程语言&#xff1f; 51 单片机规模小得拮据&#xff0c;C 的优势几乎看不到。放个类型信息进去都费劲&#xff0c;你还想用虚函数&#xff1f;还想模板展开&#xff1f;程序轻松破 10k。最近很多小伙伴找我&#xff0c;说想要一些…...

利用HTTP2,新型DDoS攻击峰值破纪录

亚马逊、Cloudflare 和谷歌周二联合发布消息称&#xff0c;一种依赖于 HTTP/2 快速重置技术的攻击行为对它们造成了破纪录的分布式拒绝服务 (DDoS) 攻击。 根据披露的信息&#xff0c;该攻击自8月下旬以来便一直存在&#xff0c;所利用的漏洞被跟踪为CVE-2023-44487&#xff0c…...

android鼠标滚轮事件监听方法

Overridepublic boolean onGenericMotionEvent(MotionEvent event) { //The input source is a pointing device associated with a display. //输入源为可显示的指针设备&#xff0c;如&#xff1a;mouse pointing device(鼠标指针),stylus pointing device(尖笔设备)if (0 ! …...

【C语言|关键字】C语言32个关键字详解(4)——其他(typedef、sizeof)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

Hafnium简介和构建

安全之安全(security)博客目录导读 目录 一、Hafnium简介 二、Hafnium构建 2.1.1 先决条件 2.1.1.1 构建Host 2.1.1.2 工具链 2.1.1.3 依赖 2.1.1.4 获取源码 2.1.2 构建 一、Hafnium简介 可信固件为Armv8-A、Armv9-A和Armv8-M提供了安全软件的参考实现。它为SoC开发人…...

2023年香水行业数据分析:国人用香需求升级,高端香水高速增长

在人口结构变迁的背景下&#xff0c;“Z世代”作为当下我国的消费主力&#xff0c;正在将“悦己”消费推动成为新潮流。具备经济基础的“Z世代”倡导“高颜值”、“个性化”、“精致主义”&#xff0c;这和香水、香氛为代表的“嗅觉经济”的特性充分契合&#xff0c;因此&#…...

这可能是最简单的Page Object库

做过web自动化测试的同学&#xff0c;对Page object设计模式应该不陌生。 Page object库应该根据以下目标开发&#xff1a; Page object应该易于使用 清晰的结构 PageObjects 对于页面对象 PageModules对于页面内容 只写测试&#xff0c;而不是基础。 在可能的情况下防止…...

论文阅读——BERT

ArXiv&#xff1a;https://arxiv.org/abs/1810.04805 github&#xff1a;GitHub - google-research/bert: TensorFlow code and pre-trained models for BERT 一、模型及特点&#xff1a; 1、模型&#xff1a; 深层双向transformer encoder结构 BERT-BASE&#xff1a;(L12, H…...

竞赛 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满…...

Springboot创建多数据源

yml文件 spring:datasource:dynamic:# 设置默认的数据源或者数据源组,默认值即为 masterprimary: masterdatasource:# 主库数据源master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://xxx.xxx.xxx.xxx:3306/test?useUnicodetrue&characterEncodingutf8…...

【Hello Algorithm】滑动窗口内最大值最小值

滑动窗口介绍 滑动窗口是一种我们想象中的数据结构 它是用来解决算法问题的 我们可以想象出一个数组 然后再在这个数组的起始位置想象出两个指针 L 和 R 我们对于这两个指针做出以下规定 L 和 R指针只能往右移动L指针不能走到R指针的右边我们只能看到L指针和R指针中间的数字 …...

HTML,CSS实现鼠标划过头像,头像突出变大(附源码)

话不多说&#xff0c;先上代码 先看原图&#xff1a; 再看 鼠标放上去后的图&#xff1a; 是不是明显感觉到 人物头像突出了一些&#xff0c;而且还增加了阴影部分的效果呢&#xff1f; 直接上代码&#xff01;&#xff01;&#xff01; <!--由于我的 img 标签放的是循环后…...

“爱知道”,你知道吗?

拥抱时代浪潮&#xff0c;加速科技变革。数字经济时代&#xff0c;杭州重点贯彻市委市政府数字经济创新提质“一号发展工程”&#xff0c;加快发展数字经济&#xff0c;推动全市数字经济往高攀升、向新进军、以融提效。基于政府对数字经济新活力的赋能、优化数字社会环节、构建…...

基于SpringBoot+Vue的服装销售系统

基于SpringBootVue的服装销售平台的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 我的订单 登录界面 管理员界面 摘要 基于SpringBoot和Vue的服装销售系统…...

针对多分类问题,使用深度学习--Keras进行微调提升性能

前面的文章对二分类问题用Keras进行了Fine-tune,使得模型的准确率进一步提升,此处对于多分类问题,尝试使用Fine-tune来提升性能。 1. 准备数据集 为了演示,本次选用了博文keras系列︱图像多分类训练与利用bottleneck features进行微调(三)中提到的数据集,原始的数据集…...

一、【Photoshop如何根据不同类型图像抠图】

文章目录 前言图形结构1、规则图形2、不规则图形 图形颜色1、轮廓清晰2、颜色分明 前言 当我们有抠图需求的时候&#xff0c;不要一开始就想着我怎么去把它抠出来&#xff0c;首先应该分析图形的特点&#xff0c;然后再去选取合适的工具&#xff0c;这样才可以做到事半功倍&am…...

rust - 理解borrow trait

简介 borrow trait 是处理借用(即其它语言中的引用)的 trait,变量的所有权不会转移.泛型定义如下: pub trait Borrow<Borrowed: ?Sized> {/// Immutably borrows from an owned value.fn borrow(&self) -> &Borrowed; }其中包含一个 borrow(&self)的方…...

review-java-basis

Path环境变量用于记住程序路径&#xff0c;方便在命令行窗口的任意目录启动程序 \n代表换行的意思&#xff0c;/t代表一个tab前进一格 强转可能导致数据的丢失&#xff08;溢出&#xff09; 浮点型转换为整型&#xff0c;直接丢掉小数部分&#xff0c;保留整数部分返回 数据类…...