Qt网络编程——QTcpServer和QTcpSocket
文章目录
- 核心API
- TCP回显服务器
- TCP回显客户端
核心API
QTcpServer
用于监听端口和获取客户端连接
名称 | 类型 | 说明 | 对标原生API |
---|---|---|---|
listen(const QHostAddress&, quint16 port) | 方法 | 绑定指定的地址和端口号,并开始监听 | bind和listen |
nextPendingConnection() | 方法 | 从系统中获取到一个建立好的tcp连接 返回一个 QTcpSocket ,表示这个客户端的连接通过这个socket对象完成和客户端之间的通信 | accept |
newCondition() | 信号 | 有新的客户端建立好连接之后触发 | 无(类似IO多路复用的通知机制) |
QTcpSocket
用于客户端和服务器之前的数据交互
tcp读取的数据是字节流,因此读取和返回的都是字节数组,这和udp的
QNetworkDatagram
数据报不一样
事件循环,可以简单理解为是Qt程序内部一个带有“生物钟”这样的东西,周期性执行一些逻辑
名称 | 类型 | 说明 | 对标原生API |
---|---|---|---|
readAll() | 方法 | 读取当前接收缓冲区的所有数据 返回QByteArray对象 | read |
write(const QByteArray&) | 方法 | 将数据写入socket当中 | write |
deleteLater | 方法 | 暂时把socket对象标记为无效 Qt会在下一个事件循环中构造释放该对象 | 无 |
readyRead | 信号 | 有数据到达并准备就绪时触发 | 无 |
disconnected | 信号 | 连接断开时触发 | 无 |
QByteArray
是字节数组,可以和QString
互相转换
QString
的构造函数可以把QByteArray
转换成QString
QString
的toUtf8
函数可以把QString
转成QByteArray
TCP回显服务器
用这些接口,写一个回显服务器。
创建项目之后,如果要进行网络编程,第一步就是在
.pro
文件中加入network
模块
界面:
widget.h
:
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void processConnection();QString process(const QString request);
private:Ui::Widget *ui;QTcpServer *tcpServer;
};
#endif // WIDGET_H
widget.cpp
:
-
绑定和监听端口号一定是要等准备工作做完之后再进行,比如说如何处理连接、如何处理请求等…
-
需要手动释放
clientSocket
,因为它是每个客户端都有这样一个对象,而QTcpServer
和QUdpServer
都是只有一份。如果不对断开连接的客户端进行释放,累计的客户端会越来越多,这会导致两个问题:文件描述符泄漏和内存泄漏。也不能直接
delete clientSocket
,因为当前槽函数主要是围绕clientSocket
来进行操作的,一旦delete
,其他逻辑就无法使用clientSocket
,使用要保证delete
操作是最后一步,而且不会被return或者抛出异常给跳过。Qt提供了
deleteLater
,不是立即销毁,而是告诉Qt,下一轮事件循环中,再进行上述销毁操作。槽函数是在事件循环中进行的,进入下一轮事件循环表明上一轮事件肯定结束了。
#include "widget.h"
#include "ui_widget.h"
#include<QMessageBox>
#include<QTcpSocket>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//修改窗口标题this->setWindowTitle("tcp服务器");//创建QTcpServer实例tcpServer = new QTcpServer(this);//连接信号槽(如何处理连接)connect(tcpServer, &QTcpServer::newConnection, this, &Widget::processConnection);//绑定并监听端口号if(!tcpServer->listen(QHostAddress::Any, 8080)){QMessageBox::critical(this, "服务器启动失败", tcpServer->errorString());return;}
}Widget::~Widget()
{delete ui;
}void Widget::processConnection()
{//拿到socket对象QTcpSocket *clientSocket = tcpServer->nextPendingConnection();//peerAddress表示对端的ip地址QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] online";//显示到界面ui->listWidget->addItem(log);//通过信号槽处理客户端发来的请求connect(clientSocket, &QTcpSocket::readyRead, this, [=](){//读取请求QString request = clientSocket->readAll();//处理请求const QString &response = process(request);//返回响应clientSocket->write(response.toUtf8());//记录日志QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "]"+ "req: " + request + ", resp: " + response;ui->listWidget->addItem(log);});//客户端断开连接//disconnected表示已经断开,是一个信号connect(clientSocket, &QTcpSocket::disconnected, this, [=](){QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] offline";ui->listWidget->addItem(log);//手动释放clientSocketclientSocket->deleteLater();});
}QString Widget::process(const QString request)
{return request;
}
此段代码,从某种意义上来说,不够严谨,因为tcp是面向字节流的,可能会分为多段。
更好的做法是,将收到的数据,放到一个较大字节的缓冲区当中,然后按照约定好的协议,进行数据解析提取。
TCP回显客户端
ui界面:
对于客户端,使用的就是
QTcpSocket
,QTcpServer
只是在服务端使用的
- 调用
connectToHost
函数,此时系统就开始和对方服务器三次握手,三次握手也是需要时间的,而这个函数并不会阻塞等待握手完毕,是一个非阻塞的函数。
所以需要搭配waitForConnected
,等待连接建立成功
#include "widget.h"
#include "ui_widget.h"
#include<QMessageBox>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置窗口标题this->setWindowTitle("客户端");//创建socket对象实例socket = new QTcpSocket(this);//和服务器建立连接socket->connectToHost("127.0.0.1", 8080);//连接信号槽connect(socket, &QTcpSocket::readyRead, this, [=](){//读取响应内容QString response = socket->readAll();//响应内容显示到界面ui->listWidget->addItem("server say# " + response);});//等待连接建立结果if(!socket->waitForConnected()){QMessageBox::critical(this, "连接服务器失败", socket->errorString());return;}}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{//获取输入框内容const QString &text = ui->lineEdit->text();//发送到服务器socket->write(text.toUtf8());//将发送的消息显示到界面ui->listWidget->addItem("client say#" + text);//清空输入框内容ui->lineEdit->setText("");
}
Linux当中写Tcp服务器的时候,如果多个客户端同时访问,就只会生效一个,然后引入线程,每个客户端一个线程;
而这里并没有出现这类情况,这是因为之前是写的两层循环,里面的循环没有结束,导致外层循环不能快速调用到
accpet
,导致第二个客户端无法进行处理。引入多线程,本质上就是将双重循环,化简成两个独立的循环。
Qt里面的信号槽机制,就无需写这些循环,比较方便。
相关文章:

Qt网络编程——QTcpServer和QTcpSocket
文章目录 核心APITCP回显服务器TCP回显客户端 核心API QTcpServer用于监听端口和获取客户端连接 名称类型说明对标原生APIlisten(const QHostAddress&, quint16 port)方法绑定指定的地址和端口号,并开始监听bind和listennextPendingConnection()方法从系统中获…...

CentOS 7 aarch64制作openssh 9.9p1 rpm包 —— 筑梦之路
本篇文章还是基于开源项目openssh-rpms制作。 https://github.com/boypt/openssh-rpms.git 官方发行说明: OpenSSH: Release Notes 1. 修改version.env 2. 下载源码包 openssl网站改版,下载地址和之前不一样了 # 下载openssl1.1.1w源码包cd downlo…...
Flink和Spark的区别
1、设计理念不同 flink:Flink是基于事件驱动的,是面向流的处理框架, Flink基于每个事件一行一行地流式处理,是真正的流式计算. 另外他也可以基于流来模拟批进行计算实现批处理。 spark:Spark的技术理念是使用微批来模拟流的计算,…...
以太网开发基础-MAC和PHY
直接参考: 以太网基础-MAC和PHY-CSDN博客 路由器上一般有三类MAC地址 给一个范例: 00:0C:E5:4B:F2:85 这个地址就可以作为LAN MAC地址 00:0C:E5:4B:F2:86 这个地址就可以作为WAN MAC地址 00:0C:E5:4B:F2:87 这个地址就可以作为无线 MAC地址 通常,路由器…...

Java 发布jar包到maven中央仓库(2024年9月保姆级教程)
文章目录 前言一、账号准备1. 注册登录账号2. 新建命名空间3. 验证命名空间4. 生成令牌5. 为 maven 设置令牌二、GPG准备1. 下载GPG2. 发布证书2.1 新建证书2.2 发布证书到服务器2.3 验证发布三、发布jar包到中央仓库1. 编辑项目pom文件2. 打包上传3. 发布jar包4. 搜索我们的ja…...

Pandas和Seaborn可视化详解
1.Pandas绘图-单变量 概述 pandas库是Python数据分析的核心库 它不仅可以加载和转换数据,还可以做更多的事情:它还可以可视化 pandas绘图API简单易用,是pandas流行的重要原因之一 可视化小技巧: 如果是类别型 柱状 饼图 (类别相对较少 5-…...

【Python】Windows下安装使用FFmpeg
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。之前为了MP3转wav,需要pip安装并import AudioSegment,但是会报错:FileNotFoundError: [WinError 2] 系统找不到指定的文件。 因为FFmpeg需要另…...

LLM - 使用 XTuner 指令微调 多模态大语言模型(InternVL2) 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/142528967 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 XTuner…...

【Python】数据可视化之热力图
热力图(Heatmap)是一种通过颜色深浅来展示数据分布、密度和强度等信息的可视化图表。它通过对色块着色来反映数据特征,使用户能够直观地理解数据模式,发现规律,并作出决策。 目录 基本原理 sns.heatmap 代码实现 基…...

个人博客系统测试(selenium)
P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。 P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。 博主主页:Yan. yan. …...

【速成Redis】01 Redis简介及windows上如何安装redis
前言: 适用于:需要快速掌握redis技能的人(比如我),在b站,找了个课看。 01.课程简介_哔哩哔哩_bilibili01.课程简介是【GeekHour】一小时Redis教程的第1集视频,该合集共计19集,视频…...
入侵检测系统(IDS)和入侵预防系统(IPS)
入侵检测系统(IDS)和入侵预防系统(IPS)是网络安全领域中用来检测和防止潜在的恶意活动或政策违规行为的系统。它们的主要目的是保护网络和主机不受未授权访问和各种形式的攻击。以下是它们的主要区别和功能: 一&#…...
pytorch 加载模型参数后 如何测试数据,应用模型预测数据,然后连续变量转换成 list 或者numpy.array padans并保存到csv文件中
在PyTorch中,加载模型参数后测试数据通常涉及以下几个步骤: 1. **加载模型**:首先,你需要定义模型的结构,然后加载预训练的参数。 2. **加载数据**:准备你的测试数据集。确保数据集已经正确地预处理&…...
uni-app开发流程(开发、预览、构建和发布过程)
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,支持编写一次代码,生成可以在多个平台(如微信小程序、H5、App等)运行的应用。下面是 uni-app 的开发流程,包括从创建项目到部署的各个阶段。 1. 创建项目 通过 HB…...
Linux Shell: 使用 Expect 自动化 SCP 和 SSH 连接的 Shell 脚本详解
文章目录 0. 引言2. 解决方案3. 脚本详解脚本1:使用 SSH 和 Expect 自动化登录远端机器脚本说明 脚本2:使用 SCP 和 Expect 自动化文件上传脚本说明 脚本3:使用 SCP 和 Expect 自动化文件下载脚本说明 4. 脚本的使用方法5. 关键技术点5.1. Ex…...

深入分析MySQL事务日志-Undo Log日志
文章目录 InnoDB事务日志-Undo Log日志2.1 Undo Log2.1.1 Undo Log与原子性2.1.2 Undo的存储格式1)insert类型Undo Log2)delete类型Undo Log3)update类型Undo Log 2.1.3 Undo Log的工作原理2.1.4 Undo Log的系统参数2.1.5 Undo Log与Purge线程…...

828华为云征文 | 在Huawei Cloud EulerOS系统中安装Docker的详细步骤与常见问题解决
前言 Docker是一种轻量级的容器技术,广泛用于应用程序的开发、部署和运维。在华为云的欧拉(Huawei Cloud EulerOS)系统上安装和运行Docker,虽然与CentOS有相似之处,但在具体实现过程中,可能会遇到一些系统…...
什么是数据增强中的插值法?
一、插值法的概念 在数据增强中,插值法是一种重要的技术,它通过数学模型在已知数据点之间估计未知数据点的值。这种方法可以帮助我们在不增加实际数据的情况下,通过生成新的数据点来扩展数据集。插值法基于这样的假设:如果已知的数…...

springboot实战学习(9)(配置mybatis“驼峰命名“和“下划线命名“自动转换)(postman接口测试统一添加请求头)(获取用户详细信息接口)
接着学习。之前的博客的进度:完成用户模块的注册接口的开发以及注册时的参数合法性校验、也基本完成用户模块的登录接口的主逻辑的基础上、JWT令牌"的组成与使用以及完成了"登录认证"(生成与验证JWT令牌)具体往回看了解的链接…...

之前做了抵押贷款,现在房市不景气,马上贷款要到期了该怎么办?
面对房贷的重压,特别是对于那些正承受高息贷款之苦的现有房产业主而言,探索有效的减负策略显得尤为重要。今天,我们共同探讨几种智慧策略,旨在帮助您巧妙减轻房贷的经济负担。 一、优化贷款结构:低息置换的魔力 当前&a…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...