Qt_网络编程

目录

1、Qt的UDP Socket

1.1 用Udp实现服务器 

1.2 用Udp实现客户端 

2、Qt的TCP Socket 

2.1 用Tcp实现服务器

2.2 用Tcp实现客户端

3、Qt的HTTP

3.1使用Qt的HTTP

结语 


前言:

        网络协议是每个平台都必须遵守的,只是不同的平台所提供的网络API不相同,而Qt具有跨平台性,因此Qt对网络编程也封装了一套自己的API。值得注意的是,在使用Qt进行网络编程之前, 需要在项目中的.pro文件中添加network模块。

1、Qt的UDP Socket

        Qt使用UDP通信,需要用到两个类,分别是:1、QUdpSocket,2、QNetworkDatagram。其中在网络通信中关于socket的相关工作都被集成在QUdpSocket类中,而数据传输用到的数据报则用QNetworkDatagram类表示(数据报包括数据内容,对方的端口号、ip地址)。

        QUdpSocket提供的接口介绍如下:

bind(const QHostAddress&, quint16)
绑定端口号、ip地址
receiveDatagram()
返回 QNetworkDatagram,即 对方发送过来的数据报
writeDatagram(const QNetworkDatagram&)
向对方发送一个QNetworkDatagram
readyRead(是一个信号)
在收到数据并准备就绪后触发

        QNetworkDatagram提供的接口介绍如下:

QNetworkDatagram(const QByteArray&, const QHostAddress& , quint16 )
通过 QByteArray, 目标IP地址,目标端⼝号构造⼀个 UDP数据报,通常用于发送数据时
data()
返回QByteArray,表示数据报内部持有的文本
senderAddress()
获取数据报中对方的IP地址
senderPort()
获取数据报中对方的端⼝号

        QByteArray是⼀个字节数组,可以和QString进行相互转换。例如: 使⽤QString的构造函数即可把QByteArray转成QString,使用QString的toUtf8函数即可把QString转成QByteArray

1.1 用Udp实现服务器 

         服务器的界面设计比较简单,因为服务器只需要显示消息即可,服务器回馈给客户端的信息也是程序自动触发的,所以只需要一个QListWidget控件即可,界面设计如下:

        1、首先在widget.h文件中创建一个QUdpSocket对象,代码如下:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void request();//槽函数private:Ui::Widget *ui;QUdpSocket* ser;
};
#endif // WIDGET_H

        2、在widget.cpp文件中new出一个QUdpSocket对象给到udp指针,并完成信号readyRead与槽函数的连接,而所有的发送、接收逻辑都在该槽函数中实现。于此同时还要完成绑定,目的是让服务器能够接收到客户端的消息。代码如下:

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QNetworkDatagram>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ser = new QUdpSocket(this);this->setWindowTitle("服务器");//设置窗口标题connect(ser,&QUdpSocket::readyRead,this,&Widget::request);//绑定操作bool ret = ser->bind(QHostAddress::Any,8080);//连接信号与槽if(!ret){QMessageBox::critical(nullptr, "服务器启动出错", ser->errorString());return;}
}Widget::~Widget()
{delete ui;
}QString ser_response(QString request)
{return "服务器说:"+request;
}void Widget::request()
{QNetworkDatagram request = ser->receiveDatagram();//获取一个请求的数据报QString request_text = request.data();//拿到数据报中的文本内容QString response_text = ser_response(request_text);//模拟服务器处理请求的动作,生成一个答复//将答复发送回去QNetworkDatagram response(request_text.toUtf8(),request.senderAddress(),request.senderPort());ser->writeDatagram(response);//在界面的listwidget中打印出以上信息QString log = "["+request.senderAddress().toString()+" "+QString::number(request.senderPort())+"]"+"客户端说:"+request_text;log+=" "+response_text;ui->listWidget->addItem(log);}

        运行结果:

        此时的运行结果什么也观察不到,原因就是服务器的接收和反馈功能都是在触发readyRead信号时才会执行的,而只有当客户端发送数据才会触发readyRead信号,所以还需要写一个客户端才能看到具体的效果。

1.2 用Udp实现客户端 

         设计一个界面,该界面包含⼀个QLineEdit , QPushButton , QListWidget。其中将要发送的文本写进QLineEdit中,点击QPushButton按钮就进行发送操作,并且发送的信息会显示在QListWidget,方便后续的查看。界面如下:

        1、和服务器一样,先在widget.h文件中创建一个QUdpSocket对象,代码如下:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();//按钮的槽函数void response();//接收的数据时,会执行该槽函数
private:Ui::Widget *ui;QUdpSocket* cli;
};
#endif // WIDGET_H

        2、首先实现发送消息的逻辑:QPushButton的槽函数,点击QPushButton时,则客户端向服务器发送信息,其次实现接收逻辑,因为客户端要拿到服务器的反馈,因此可以连接readyRead信号与槽,在槽函数中实现接收逻辑。代码如下:

#include "widget.h"
#include "ui_widget.h"
#include <QNetworkDatagram>const QString& ser_ip = "127.0.0.1";//服务器ip
const int ser_port = 8080;//服务器端口号Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);cli = new QUdpSocket(this);//设置窗口标题this->setWindowTitle("客户端");//连接信号与槽,目的是处理服务器反馈的消息connect(cli,&QUdpSocket::readyRead,this,&Widget::response);}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()//按钮的槽函数
{QString text = ui->lineEdit->text();//获取要发送给服务器的内容//构造数据报QNetworkDatagram resquest(text.toUtf8(),QHostAddress(ser_ip),ser_port);cli->writeDatagram(resquest);//发送给客户端ui->listWidget->addItem("客户端说:"+text);//将发送的内容显示在界面上ui->lineEdit->clear();//发送过后情况输入框中的内容}void Widget::response()
{QString response = cli->receiveDatagram().data();ui->listWidget->addItem("服务器说:"+response);
}

        运行结果:

2、Qt的TCP Socket 

        Qt使用TCP 通信,需要用到两个类:1、QTcpServer,2、QTcpSocket。其中QTcpServer是专门给服务器提供的类,客户端用不到该类,服务器用该类进行绑定、监听以及建立连接,连接建立好后,使用QTcpSocket类进行数据的传输和接收。

        QTcpServer提供的函数介绍如下:

listen(const QHostAddress&, quint16 port)
绑定指定的地址和端口号, 并开始监听
nextPendingConnection()
用于建立连接,返回⼀个QTcpSocket类型的指针,表示与客户端建立好了连接,通过这个指针完成与客户端的通信
newConnection (是一个信号)
与新的客户端建立好连接后触发

        QTcpSocket提供的函数介绍如下:

readAll()
读取当前接收缓冲区中的所有数据存放到QByteArray对象并返回
write(const QByteArray& )
将数据发送给对方
deleteLater()
暂时把socket对象标记为⽆效,在下个事件循环中析构释放当前对象
readyRead
在收到数据并准备就绪后触发
disconnected
连接断开时触发
connectconst QHostAddress&, quint16用于给客户端连接上服务器

2.1 用Tcp实现服务器

         Tcp实现服务器的界面逻辑和Udp相似,只需要一个QListWidget即可,界面设计如下:

         1、在widget.h文件中创建一个QUdpSocket对象,代码如下:

#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 new_cli();//建立连接时调用的槽函数private:Ui::Widget *ui;QTcpServer* ser;
};
#endif // WIDGET_H

        2、当有客户端进行连接时,服务器的QTcpServer会产生newConnection信号,说明有客户端连接服务器了,这时候可以在对应的槽函数中实现通信逻辑,即调用nextPendingConnection函数获取到QTcpSocket指针,通过该指针与新连接的客户端进行数据传输。此时,当客户端发送信息时,QTcpSocket也会产生readyRead信号,在该信号的槽函数中实现具体接收和发送逻辑,最后可以在客户端断开连接的时候,依靠信号disconnected来做一个提示。服务器的widget.cpp代码如下:

#include "widget.h"
#include "ui_widget.h"
#include <QTcpSocket>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ser = new QTcpServer(this);//设置窗口标题this->setWindowTitle("服务器");//当有新客户端来连接时,执行new_cli函数connect(ser,&QTcpServer::newConnection,this,&Widget::new_cli);//绑定、监听ser->listen(QHostAddress::Any,8080);}Widget::~Widget()
{delete ui;
}QString ser_response(QString request)
{return request;
}void Widget::new_cli()
{QTcpSocket* client = ser->nextPendingConnection();//拿到客户端的socketQString text = "["+client->peerAddress().toString()+" "+QString::number(client->peerPort())+"]"+"客户端上线";ui->listWidget->addItem(text);//lambda处理数据传输connect(client,&QTcpSocket::readyRead,this,[=](){QString request = client->readAll();//拿到客户端的请求QString response = ser_response(request);//模拟服务器处理请求,得到答复client->write(response.toUtf8());//反馈给客户端QString log = "["+client->peerAddress().toString()+" "+QString::number(client->peerPort())+"]"+"客户端说:"+request+" "+"服务器说:"+response;ui->listWidget->addItem(log);});//lambda处理断开连接connect(client,&QTcpSocket::disconnected,this,[=](){QString log = "["+client->peerAddress().toString()+" "+ QString::number(client->peerPort()) + "]客⼾端下线!";ui->listWidget->addItem(log);// 删除 clientSocketclient->deleteLater();});
}

        仅仅有一个服务器的代码是无法测试结果的,因此还需要些一个客户端代码,如下文。 

2.2 用Tcp实现客户端

        Tcp实现的客户端界面和Udp客户端界面是一样的,因此这里不再展示。不同的是,Tcp的客户端无需使用QTcpServer,直接使用QTcpSocket类进行通信即可,客户端的widget.cpp代码如下:

#include "widget.h"
#include "ui_widget.h"const QString& ser_ip = "127.0.0.1";//服务器ip
const int ser_port = 8080;//服务器端口号Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);cli = new QTcpSocket(this);//设置标题this->setWindowTitle("客户端");//连接服务器cli->connectToHost(ser_ip,ser_port);//实现客户端接收服务器反馈的逻辑connect(cli,&QTcpSocket::readyRead,this,[=](){QString ser_text = cli->readAll();ui->listWidget->addItem("服务器说:"+ser_text);});}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()//按钮的槽函数
{QString text = ui->lineEdit->text();//获取输入框的文本cli->write(text.toUtf8());//发送该文本ui->listWidget->addItem("客户端说:"+text);//显示在listwidget上ui->lineEdit->clear();//发送完成后清空输入框}

        运行结果:

        客户端关闭后:

3、Qt的HTTP

         Qt对HTTP协议做了封装,以供开发者方便使用HTTP协议进行与服务器的交互。Qt使用HTTP协议的核心三个类分别是:1、QNetworkRequest,2、QNetworkAccessManager,3、QNetworkReply。

        1、其中QNetworkRequest提供的核心API如下:

QNetworkRequest(const QUrl& )
通过URL构造⼀个 HTTP 请求

        2、QNetworkAccessManager提供的核心API如下:

get(const QNetworkRequest& )
QNetworkRequest为参数, 发起⼀个 HTTP GET 请求,返回 QNetworkReply对象

        3、QNetworkReply提供的核心API如下:

readAll()
读取响应body
error()
获取出错状态
errorString()
获取出错原因的文本
finished(是一个信号)在客户端收到完整的响应数据之后触发,使用逻辑和上文的readyRead一样,即该信号触发后就可以从网络中读取内容了

3.1使用Qt的HTTP

        界面设计和上述的客户端例子一样,通过发送输入框中的文本内容给服务器,从而从服务器获取到答复,再将该答复显示在QListWidget。

        widget.h代码如下:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QNetworkAccessManager>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QNetworkAccessManager* manager;
};
#endif // WIDGET_H

         widget.cpp代码如下:

#include "widget.h"
#include "ui_widget.h"
#include <QNetworkReply>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);manager = new QNetworkAccessManager(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()//实现按钮的槽函数
{// 1. 获取到输⼊框中的 URL, 构造 QUrl 对象QUrl url(ui->lineEdit->text());// 2. 构造 HTTP 请求对象QNetworkRequest request(url);// 3. 发送 GET 请求QNetworkReply* response = manager->get(request);// 4. 通过信号槽来处理响应connect(response, &QNetworkReply::finished, this, [=]() {if (response->error() == QNetworkReply::NoError) {// 响应正确QString html(response->readAll());ui->listWidget->addItem(html);// qDebug() << html;} else {// 响应出错ui->listWidget->addItem(response->errorString());}response->deleteLater();});
}

        运行结果:

结语 

        以上就是关于Qt网络编程的讲解,网络编程在任何平台下的编写逻辑都大同小异,不同的只是细节上的问题,Qt中对网络API进行了封装,这不仅让Qt可以在不同的平台下进行网络编程,还方便了开发者的使用。

        最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1548832.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

工业缺陷检测——Windows 10本地部署AnomalyGPT工业缺陷检测大模型

0. 引言 在缺陷检测中&#xff0c;由于真实世界样本中的缺陷数据极为稀少&#xff0c;有时在几千甚至几万个样品中才会出现一个缺陷数据。因此&#xff0c;以往的模型只需在正常样本上进行训练&#xff0c;学习正常样品的数据分布。在测试时&#xff0c;需要手动指定阈值来区分…

实现语音合成的三种方法:HTML5 Web Speech 、speak-tts、百度语音合成

1. 使用HTML5 Web Speech API 1.1 使用方法 window.speechSynthesis 是HTML5 Web Speech API的一部分&#xff0c;是浏览器原生提供的文本转语音功能。它允许开发者在网页上通过JavaScript调用&#xff0c;将文本转换为语音进行播放。 https://developer.mozilla.org/zh-CN/d…

渗透测试--文件上传常用绕过方式

文件上传常用绕过方式 1.前端代码&#xff0c;限制只允许上传图片。修改png为php即可绕过前端校验。 2.后端校验Content-Type 校验文件格式 前端修改&#xff0c;抓取上传数据包&#xff0c;并且修改 Content-Type 3.服务端检测&#xff08;目录路径检测&#xff09; 对目…

LMDeploy 量化部署实践

任务 使用结合W4A16量化与kv cache量化的internlm2_5-1_8b-chat模型封装本地API并与大模型进行一次对话 复现过程 按照教材安装环境。https://github.com/InternLM/Tutorial/blob/camp3/docs/L2/LMDeploy/readme.md 使用LMDeploy部署原版的1.8b大模型&#xff0c;占用显存2…

Centos怎么执行脚本

方法一&#xff1a;切换到shell脚本所在的目录&#xff08;此时&#xff0c;称为工作目录&#xff09;执行shell脚本 cd /data/shell ./hello.sh 方法二&#xff1a;以绝对路径的方式去执行bash shell脚本 /data/shell/hello.sh 方法三&#xff1a;直接使用bash 或sh 来执行…

Kubernetes深入详解(一)

目录 第一部分 K8s概念和架构 1、k8s概述和特性 2、K8s架构组件 3、k8s核心概念 第二部分 从零搭建k8s集群 1、搭建k8s环境平台规划 2、服务器硬件配置要求 3、搭建k8s集群部署方式 (1) 基于客户端工具kubeadm 1、安装Docker 2、添加阿里云YUM软件源 3、安 装kubea…

代码随想录Day 58|拓扑排序、dijkstra算法精讲,题目:软件构建、参加科学大会

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 图论part08**拓扑排序精讲**题目&#xff1a;117. 软件构建拓扑排序的背景解题思路&#xff1a;模拟过程 **dijkstra&#xff08;朴素版&#xff09;精讲**题目&#xff1a;47. 参加科学大会解题思…

腾讯特效 SDK

腾讯云视立方腾讯特效 SDK&#xff08;Tencent Effect&#xff09;是音视频终端 SDK &#xff08;腾讯云视立方&#xff09;的子产品 SDK 之一&#xff0c;提供美颜特效功能。基于优图精准的 AI 能力和天天 P 图丰富的实时特效处理&#xff0c;为各类视频处理场景提供丰富的产品…

SpringCloud-Netflix第一代微服务快速入门

1.springCloud常用组件 Netflix Eureka 当我们的微服务过多的时候&#xff0c;管理服务的通信地址是一个非常麻烦的事情&#xff0c;Eureka就是用来管理微服务的通信地址清单的&#xff0c;有了Eureka之后我们通过服务的名字就能实现服务的调用。 Netflix Ribbon\Feign : 客…

卫星导航定位原理学习(三)

GNSS信号体制及其性能分析 GNSS信号体制直接影响卫星导航系统的性能&#xff0c;是卫星导航系统设计的重要内容。卫星导航信号体制主要包括信号频率、信号结构、导航电文3部分。其中信号结构又包括调制波形、频率带宽、扩频码码长、码速率、码结构、信号功率等内容。导航电文设…

8086介绍

内部结构 执行部件EU&#xff08;Execution Unit&#xff09; 包含运算器、通用寄存器组、EU控制单元。 只负责控制&#xff0c;不和外部总线打交道 总线接口部件BIU&#xff08;Bus Interface Unit&#xff09; 包含指令队列缓冲器、16位指令指针寄存器IP、16位段寄存器&am…

【L波段差分干涉SAR卫星(陆地探测一号01组)】

L波段差分干涉SAR卫星&#xff08;陆地探测一号01组&#xff09; L波段差分干涉SAR卫星&#xff08;陆地探测一号01组&#xff09;是我国自主研发的重要卫星系统&#xff0c;以下是对该卫星的详细介绍&#xff1a; 一、基本信息 卫星组成&#xff1a;陆地探测一号01组由A星…

全网最适合入门的面向对象编程教程:53 Python字符串与序列化-字符串与字符编码

全网最适合入门的面向对象编程教程&#xff1a;53 Python 字符串与序列化-字符串与字符编码 摘要&#xff1a; 在 Python 中&#xff0c;字符串是文本的表示&#xff0c;默认使用 Unicode 编码&#xff0c;这允许你处理各种字符集&#xff0c;字符编码是将字符转换为字节的规则…

一文上手SpringSecurity【三】

一、认证流程分析 上篇文章当中,我们一步一步查阅源码方式对认证流程有了一些认证,本章节梳理一下整个流程,最后形成一张图,以更直观的方式来理解认证的整个流程. 1.1 认证当中步及的接口和类 1.1.1 【抽象类】AbstractAuthenticationProcessingFilter 实现了GenericFilter…

OFDM通信系统发射端需要做ifftshift的原因分析

对频率为15Hz的正弦波信号进行FFT分析&#xff0c;并且直接画图&#xff0c;matlab代码如下&#xff1a; fs 100; % sampling frequency t 0:(1/fs):(10-1/fs); % time vector S cos(2*pi*15*t); n length(S); X fft(S); f (0:n-1)*(fs/n); %frequenc…

使用canvas截取web camera指定区域,并生成图片

目标&#xff0c;截取红色色块背后的视频区域。 代码结构如下&#xff1a; <div id"p1"><video id"v1" autoplay playsinline></video><div id"mrz"></div><canvas id"captureCanvas"></can…

优化|深入解读DeepOPF:一种用于安全约束直流最优潮流问题的深度神经网络方法

原文信息&#xff08;包括题目、发表期刊、原文链接等&#xff09;&#xff1a; DeepOPF: A Deep Neural Network Approach for Security-Constrained DC Optimal Power Flow https://ieeexplore.ieee.org/document/9205647 原文作者&#xff1a;Xiang Pan; Tianyu Zhao; Ming…

机器学习-聚类

http://en.wikipedia.org/wiki/Multispectral_pattern_recognition 聚类基础知识 凝层次聚类 K-means 聚类 基于EM算法的聚类 聚类基础知识 聚类&#xff1a;将数据划分到不同的类里&#xff0c;使相似的数据在同一类里&#xff0c;不相似的数据在不同的类里&#xff08;物…

芝法酱学习笔记(0.5)——使用jenkins做自动打包

前言 上节讲了SpringBoot上的打包。但这些过程都是手动的&#xff0c;在实际的开发测试时&#xff0c;自动化的打包部署&#xff0c;可以大大提升团队开发的效率 一、去官网下载 1.1 官网安装命令 对于如何安装的问题&#xff0c;我向来推荐官网 wget -O /usr/share/keyri…

ThreeJs绘制圆柱体

上一章节实现了圆锥体的绘制&#xff0c;这节来绘制圆柱体&#xff0c;圆柱体就是矩形旋转获得&#xff0c;如上文一样&#xff0c;先要创建出基础的组件&#xff0c;包括场景&#xff0c;相机&#xff0c;灯光&#xff0c;渲染器。代码如下&#xff1a; initScene() {this.sce…