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…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...