【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学习(2)】P2P 通信,主要存在四种不同的网络模型的第一阶段:集中式P2P 模式 最简单的路由方式就是集中式,即存在一个中心节点保存了其他所有节点的索引信息,索引信息一般包括节点 IP 地址、端口、节…...
解决adb root命令时错误 adbd cannot run as root in production builds
我测试的手机是小米8,root权限已经刷过了,但是在pc端使用adb root命令的时候,会报错"adbd cannot run as root in production builds" 后来查资料发现是因为Magisk和安卓9版本的问题 https://www.cnblogs.com/jeason1997/p/124105…...
操作系统中套接字和设备独立性软件的关系
网络编程就是编写程序让两台联网的计算机相互交换数据。在我们不需要考虑物理连接的情况下,我们只需要考虑如何编写传输软件。操作系统提供了名为“套接字”,套接字是网络传输传输用的软件设备。 这是对软件设备的解释: 在操作系统中&#…...
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文件查找
用的是递归调用, (递归死循环的结果是导致栈内存溢出错误) 一.代码 package org.example;import java.io.File;public class day03 {public static void main(String[] args) {//文件查找,在d: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微服务 【实用篇】| 认识微服务
目录 一:认识微服务 1. 微服务框架介绍 2. 服务架构演变 3. 微服务技术对比 4. SpringCloud 图书推荐:《巧用ChatGPT快速提高职场晋升力》 一:认识微服务 本课程学习于黑马,会通过分层次学习,分为三部分去讲解微…...
Csdn文章编写参考案例
这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…...
Jmeter性能测试:高并发分布式性能测试
一、为什么要进行分布式性能测试 当进行高并发性能测试的时候,受限于Jmeter工具本身和电脑硬件的原因,无法满足我们对大并发性能测试的要求。 基于这种场景下,我们就需要采用分布式的方式来实现我们高并发的性能测试要求。 二、分布式性能…...
2015年亚太杯APMCM数学建模大赛B题城市公共交通服务水平动态评价模型求解全过程文档及程序
2015年亚太杯APMCM数学建模大赛 B题 城市公共交通服务水平动态评价模型 原题再现 城市公共交通服务评价是城市公共交通系统建设和提高公共交通运营效率的重要组成部分。对于公交企业,管理和规划部门,传统公交车站、线路和换乘枢纽的规划数据只是基于主…...
CCF CSP认证历年题目自练 Day40
题目 试题编号: 201412-3 试题名称: 集合竞价 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量…...
闲聊一下写技术博客的一些感想
大家好,我是阿赵。 在我的163博客关闭之后,我就把一部分的博文移到了CSDN这边。不过实际上我有好几年都没有写过博客,所以这个博客的浏览量和粉丝数一直都不高。直到今年2023年的2月底开始,打算总结一下3DsMax的MaxScript的用…...
单片机为什么一直用C语言,不用其他编程语言?
单片机为什么一直用C语言,不用其他编程语言? 51 单片机规模小得拮据,C 的优势几乎看不到。放个类型信息进去都费劲,你还想用虚函数?还想模板展开?程序轻松破 10k。最近很多小伙伴找我,说想要一些…...
利用HTTP2,新型DDoS攻击峰值破纪录
亚马逊、Cloudflare 和谷歌周二联合发布消息称,一种依赖于 HTTP/2 快速重置技术的攻击行为对它们造成了破纪录的分布式拒绝服务 (DDoS) 攻击。 根据披露的信息,该攻击自8月下旬以来便一直存在,所利用的漏洞被跟踪为CVE-2023-44487,…...
android鼠标滚轮事件监听方法
Overridepublic boolean onGenericMotionEvent(MotionEvent event) { //The input source is a pointing device associated with a display. //输入源为可显示的指针设备,如:mouse pointing device(鼠标指针),stylus pointing device(尖笔设备)if (0 ! …...
【C语言|关键字】C语言32个关键字详解(4)——其他(typedef、sizeof)
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&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年香水行业数据分析:国人用香需求升级,高端香水高速增长
在人口结构变迁的背景下,“Z世代”作为当下我国的消费主力,正在将“悦己”消费推动成为新潮流。具备经济基础的“Z世代”倡导“高颜值”、“个性化”、“精致主义”,这和香水、香氛为代表的“嗅觉经济”的特性充分契合,因此&#…...
这可能是最简单的Page Object库
做过web自动化测试的同学,对Page object设计模式应该不陌生。 Page object库应该根据以下目标开发: Page object应该易于使用 清晰的结构 PageObjects 对于页面对象 PageModules对于页面内容 只写测试,而不是基础。 在可能的情况下防止…...
论文阅读——BERT
ArXiv:https://arxiv.org/abs/1810.04805 github:GitHub - google-research/bert: TensorFlow code and pre-trained models for BERT 一、模型及特点: 1、模型: 深层双向transformer encoder结构 BERT-BASE:(L12, H…...
4个高效步骤实现HMCL启动器数据无忧迁移全攻略
4个高效步骤实现HMCL启动器数据无忧迁移全攻略 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL 当你终于升级了新电脑,兴冲冲地安装好HMCL启动器准备…...
【书生·浦语】internlm2-chat-1.8b部署避坑指南:模型拉取失败/响应延迟/中文乱码全解
【书生浦语】internlm2-chat-1.8b部署避坑指南:模型拉取失败/响应延迟/中文乱码全解 1. 环境准备与快速开始 在开始使用internlm2-chat-1.8b之前,我们先来了解一下这个模型的基本情况。这是一个拥有18亿参数的中文对话模型,专门针对聊天场景…...
Ollama部署Phi-3-mini完整指南:从安装到实战应用场景解析
Ollama部署Phi-3-mini完整指南:从安装到实战应用场景解析 1. 为什么选择Phi-3-mini-4k-instruct? Phi-3-mini-4k-instruct是微软推出的轻量级AI模型,虽然只有38亿参数,但在多个基准测试中表现优异。这个模型特别适合需要快速部署…...
揭秘宇树科技G1人形机器人:消费级市场的破局者与挑战
1. G1人形机器人:消费级市场的颠覆者 当身高1.3米的G1人形机器人站在我面前时,第一感觉是"这玩意儿居然不到10万"。作为宇树科技进军消费级市场的首款产品,G1确实在价格和体积上做了精准定位。相比那些动辄几十万的工业级机器人&am…...
STM8S001单片机:8引脚高性价比嵌入式开发方案
1. STM8S001单片机:小身材大能量的性价比之王 在嵌入式开发领域,我们常常陷入一个两难选择:要么使用功能强大但引脚众多、价格昂贵的高端MCU,要么选择功能简陋、开发环境不友好的廉价芯片。STMicroelectronics最新推出的STM8S001系…...
用rosbags工具5分钟搞定ROS1/ROS2数据包转换(含自定义消息处理技巧)
5分钟极速转换ROS1/ROS2数据包:rosbags工具高阶实战指南 在机器人开发领域,数据包的兼容性问题一直是开发者面临的痛点。当我们需要在ROS1和ROS2之间迁移项目时,传统方法往往需要复杂的桥接配置和漫长的等待时间。今天要介绍的rosbags工具&am…...
号令天下:守财数字能量号组413与313能守财吗
在数字能量学的体系中,延年磁场是主导守财的核心能量,天医磁场主打招财纳福,生气磁场侧重拓展人脉,二者并不具备直接的守财属性。像 413、313 这类组合,核心作用集中在招财聚财方面,守财能力相对薄弱&#…...
OpenClaw多模型切换:Qwen2.5-VL-7B与文本模型协同工作
OpenClaw多模型切换:Qwen2.5-VL-7B与文本模型协同工作 1. 为什么需要多模型协同 去年夏天,当我第一次尝试用OpenClaw自动化处理团队的知识库文档时,遇到了一个棘手的问题:有些文档包含大量截图和图表说明,而纯文本模…...
程序内存管理:堆与栈的核心原理与应用
1. 内存分配基础概念解析在计算机编程中,内存管理是每个程序员必须掌握的核心技能。程序运行时,操作系统会为其分配一块虚拟内存空间,这块空间被划分为几个关键区域,每个区域都有其特定的用途和管理方式。1.1 程序内存布局典型的程…...
利用drawio高效绘制数据库ER图:从入门到精通
1. 为什么选择drawio绘制数据库ER图 第一次接触数据库设计时,我被各种专业工具的价格和复杂度吓退了。直到发现drawio这个宝藏工具,才真正体会到什么叫"用最简单的工具做专业的事"。作为一款完全免费的跨平台工具,drawio不仅支持网…...
