[Qt]系统相关-网络编程-TCP、UDP、HTTP协议

目录

前言

一、UDP网络编程

1.Qt项目文件

2.UDP类

QUdpSocket

QNetworkDatagram

3.UDP回显服务器案例

细节

服务器设计

客户端设计

二、TCP网络编程

1.TCP类

QTcpServer

QTcpSocket

2.TCP回显服务器案例

细节

服务器设计

客户端设计

三、HTTP客户端

1.HTTP客户端类 

QNetworkAccessManager

QNetworkRequest

QNetworkReply

2.HTTP客户端案例


前言

        我们之前学习的系统相关的内容,在不同的系统下的理论和实现可能都不太一样,但是对于计算机网络模块来说,因为网络提供了不同主机之间的信息通信,那么如何想让两个主机进行通信,那么他们的通信模块,也就是计算机模块的实现也就必须是一样的才可以。所以说计算机网络模块的实现对于不同的系统也是一样的,最主要的区别就是在于语言层面上,对于网络编程的系统接口的封装。对于C++标准库中,一直是没有提供网络编程相关的API库。

        在整个网络协议栈来看,网络编程就是我们对于用户层的一种编写,但是我们想要传输数据的时候需要传输层协议的支持,但是传输层协议有两个,所以我们在应用层也需要采用一些接口去指定传输层协议。

一、UDP网络编程

1.Qt项目文件

        .pro文件是 Qt 项目文件。它是一个文本文件,包含了项目的各种信息和配置,用于指导qmake如何构建 Qt 项目。所以在Qt中进行网络编程之前,需要在项目当中的.pro文件中添加network模块来引入网络编程模块。在我们之前使用的所有控件都是包含在QtCore模块当中的,只不过默认生成.pro文件的时候就已经添加了。而且Qt来提供了很多其他的模块。

        Qt为什么要划分出这么多模块呢?因为Qt本身是一个非常大的框架,如果我们默认把所有Qt提高的功能模块全都一下引入项目当中,那么即使我们写一个简单的打印helloworld,那么生成的可执行程序也会 非常的大,可执行程序内部编译了许多用不到的内容。所以为了让生成的Qt项目更加的轻量化,那么就把不同的功能划分成了多个模块,我们需要使用的时候,就需要在.pro文件中引入包含了。

        而且为了让多模块的项目更加的轻量化,Qt也提高了模块的动态库和静态库的两种版本。 

2.UDP类

        Qt对于UDP的类有两个,一个是QUdpSocket表示udp通信套接字文件类,另一个是表示一个UDP数据报的类QNetworkDatagram类。

QUdpSocket
名称说明

bind(const QHostAddress&,  quint16)

绑定指定的端口号
receiveDatagram()返回一个UDP数据报对象
writeDatagram(const QNetworkDatagram&)发送一个UDP数据报
readyRead信号在收到数据并准备就绪后触发
  • 对于读取数据的操作,在C++语言层面的接口或者系统的底层原生接口默认都是阻塞方式的等待,当然也可以设置非阻塞,而Qt在处理读取数据操作的时候,并不是阻塞或者非阻塞等待的方式,而是采用信号槽机制,当有数据到来并就绪只会,就会发送readRead信号。
  • QHostAddress是一个用于表示IP地址的一个类,对于服务器来说设置为QHostAddress::Any即可,表示可以用于监听任何地址的连接,对于IPv4和IPv6都适用。
  • 对于bind函数可能会绑定失败,但是他会将失败的原因存放起来,可以通过errorString成员函数获取到失败信息。
QNetworkDatagram
名称说明
QNetworkDatagram(const QByteArray&, const HostAddress&, quint16)构造函数,通过QByteArray,目标ip和端口号构造一个UDP数据报
data()获取数据报内部持有的数据,返回一个QByteArray类型对象
senderAddress()获取数据报中包含的对端ip地址
senderPort()获取数据报中包含的对端端口号

3.UDP回显服务器案例

        只是一个使用网络接口的案例,因为一般来说服务器都不会带有图形化界面的。

细节
  • 在readyRead信号绑定槽函数和bind操作的顺序来说,要先绑定信号槽,后bind,因为一旦绑定ip和端口号之后,就可能会有通信数据到来了。那么在进行信号槽的绑定,就会来不及了,早到的数据就因为没有槽函数,所以不进行处理了。
  • 我们下面的服务器设计中带有了图形化界面,在配置文件.pro文件中也可以看到我们引入了gui模块,那么我们的云服务器默认是没有装配图形化界面的,所以是没有办法直接将我们下面写的服务器端代码放入到云服务器允许的。
  • 而对于我们现在写的Qt的udp客户端是可以直接连接linux服务器下的udp服务器的。所以说网络底层协议的实现都是一样的。udp都是一套逻辑。一般Qt都不会写服务器,大多数都是写客户端,然后用Qt客户端连接linux服务器。
服务器设计

widget.h文件

class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();QString porcess(const QString& request);public slots:void processRequest();private:Ui::Widget *ui;//引入Udp成员QUdpSocket* socket;
};

widget.cpp文件 

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QNetworkDatagram>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建udp对象socket = new QUdpSocket(this);//设置窗口标题this->setWindowTitle("服务器");//连接信号槽connect(socket, &QUdpSocket::readyRead, this, &Widget::processRequest);//绑定端口号bool retbind = socket->bind(QHostAddress::Any, 8082);if(retbind == false){QMessageBox::critical(this, "服务器启动出错", socket->errorString());return;}}Widget::~Widget()
{delete ui;
}//但是我们这里是回显,所以没有什么处理过程
QString Widget::porcess(const QString &request)
{return request;
}void Widget::processRequest()
{//获取请求信息const QNetworkDatagram& udp_request =  socket->receiveDatagram();//转化为字符串类型QString data_request = udp_request.data();//处理请求const QString& data = porcess(data_request);//构建相应数据报QNetworkDatagram response(data.toUtf8(), udp_request.senderAddress(), udp_request.senderPort());//发送回客户端socket->writeDatagram(response);//把客户端发的信息显示到listWidget控件上QString log = "[" + udp_request.senderAddress().toString() + ":" + QString::number(udp_request.senderPort())+ "]" + "message:" + data_request;ui->listWidget->addItem(log);
}
客户端设计

widget.h文件

class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;//引入udp对象QUdpSocket* socket;
};

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include <QNetworkDatagram>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置窗口名称this->setWindowTitle("客户端");//创建udp对象socket = new QUdpSocket(this);//连接信号槽connect(socket, &QUdpSocket::readyRead, this, [=](){//获取数据报const QNetworkDatagram udp_response = socket->receiveDatagram();//读取数据const QString& data = udp_response.data();//写入对话框中ui->listWidget->addItem("服务器:" + data);});
}Widget::~Widget()
{delete ui;
}
//发送按钮
void Widget::on_pushButton_clicked()
{//获取输入框的内容const QString& text = ui->lineEdit->text();//构建请求数据报const QString ip = "127.0.0.1";const quint16 port = 8082;QNetworkDatagram data_request(text.toUtf8(), QHostAddress(ip), port);//发送数据socket->writeDatagram(data_request);//更新对话框中的内容ui->listWidget->addItem("客户端:" + text);//情况输入框ui->lineEdit->clear();
}

二、TCP网络编程

1.TCP类

        Qt对于TCP的类提供两个,第一个是QTcpServer用于监听端口,实现获取客户端连接的操作,相当于是listensocket以及对于bind、listen以及accept接口函数的一个封装。第二个是用于客户端和服务器之间数据交互的类QTcpSocket类。

QTcpServer
名称说明
listen(const QHostAddress&, quint16 port)绑定ip和端口号,并开始监听,相当于bind和listen的结合
nextPendingConnection()从系统当中获取到一个已经建立好的tcp连接,返回一个QTcpSocket对象,通过这个对象是实现与客户端之间的通信
newConnection信号有新的客户端建立连接完毕之后触发的信号
QTcpSocket
名称说明
readAll()读取当前接收缓冲区中的所有数据,返回QByteArray对象
write(const QByteArray&)把输入写入到socket的发送缓冲区中
deleteLater()暂时把socket对象标记为无效,Qt会在下个事件循环中析构释放该对象、
peerAddress()获取对端ip地址
peerPort()获取对端端口号

connectToHost( const QString &hostName, quint16 port)

向服务器发起连接
readyRead信号有数据到来并准备就绪触发
disconnected信号连接断开的时候触发

2.TCP回显服务器案例

细节
  • 对于客户端向服务器发起连接的connectToHost函数返回值为void类型,但是我们还是要判断是否连接成功了,所以QTcpSocket类中提供了waitForConnected函数,该函数的作用是让当前线程处理等待状态,直到连接成功,或者连接反馈错误为止,又或者说超时。
服务器设计

widget.h文件

class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void processConnection();private:Ui::Widget *ui;//引入Tcp对象QTcpServer* socket;
};

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置窗口标题this->setWindowTitle("服务器");//tcp对象实例化socket = new QTcpServer(this);//绑定newConnection的信号槽函数connect(socket, &QTcpServer::newConnection, this, &Widget::processConnection);//进行bind和listen操作bool retlisten = socket->listen(QHostAddress::Any, 8082);if(retlisten == false){QMessageBox::critical(this, "服务器启动失败", socket->errorString());return;}
}Widget::~Widget()
{delete ui;
}//获取新连接的信号处理函数
void Widget::processConnection()
{//获取新连接QTcpSocket* client = socket->nextPendingConnection();//构建日志QString log = "[" + client->peerAddress().toString() + ":" + QString::number(client->peerPort()) + "] 新客户端上线";ui->listWidget->addItem(log);//通过信号槽触发接收消息connect(client, &QTcpSocket::readyRead, this, [=](){//读取消息QString message = client->readAll();//处理消息--此处没有处理,只是回显//写回到客户端client->write(message.toUtf8());//构建日志QString log = "[" + client->peerAddress().toString() + ":" + QString::number(client->peerPort()) + "] say: " + message;//写到界面ui->listWidget->addItem(log);});//处理断开连接的信号槽函数connect(client, &QTcpSocket::disconnected, this, [=](){//构建日志QString log = "[" + client->peerAddress().toString() + ":" + QString::number(client->peerPort()) + "] 客户端下线";//释放对象client->deleteLater();});
}
客户端设计

widget.h文件

class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;//构建tcp对象QTcpSocket* socket;
};

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置窗口标题this->setWindowTitle("客户端 ");//实例化tcp对象socket = new QTcpSocket(this);//向服务器发起连接socket->connectToHost("127.0.0.1", 8082);//确认是否连接成功if(!socket->waitForConnected()){QMessageBox::critical(this, "连接服务器出错", socket->errorString());return;}//绑定接收到消息的信号槽函数connect(socket, &QTcpSocket::readyRead, this, [=](){//获取接收到的内容QString message = socket->readAll();//将内容打印到对话框中QString log = "服务器: " + message;ui->listWidget->addItem(log);});
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{//获取输入框的内容QString message = ui->lineEdit->text();//将内容发送给服务器socket->write(message.toUtf8());//将内容打印到对话框中ui->listWidget->addItem("客户端: " + message);//情况输入框ui->lineEdit->clear();
}

三、HTTP客户端

1.HTTP客户端类 

        Qt中为HTTP协议的客户端主要提供了三个类,一个是QNetworkAccessManager类,该类提供了HTTP有关的核心操作。第二个类是QNetworkRequest类表示一个不含body的HTTP请求。第三个类就是QNetworkReply类,表示一个HTTP的响应。

        上述也说了真正的服务器一定也不会使用Qt就实现,所以Qt就没有提供服务端相关的HTTP类。

QNetworkAccessManager
方法说明
get(const QNetworkRequest&)发起一个HTTP GET请求,返回一个QNetworkReply对象
post(const QNetworkRequest&, const QByteArray&)发起一个HTTP POST请求,也返回一个QNetworkReply对象
QNetworkRequest

        一个HTTP协议的完整报文应该是包括报头和有效载荷的,而这个类只是实现了一个报头,对于有效载荷该类不进行实现,而且对于请求报文来说一般都不会带有一些实质性的内容,只会传递一些kv形式的参数内容,通过post方法来传递,所以post方法也为我们提供了传递kv的参数。

方法说明
QNetworkRequest(const QUrl&)通过Url构造一个HTTP请求
setHeader(QNetworkRequest::knownHeaders header, const QVariant& value)设置请求头部字段

        对于报头的请求行字段,Qt也进行了一定的封装,方便我们去设置请求行,Qt中采用的是枚举类型将常用的请求行字段进行一一列举出来,QNetworkRequest::knownHeaders就是该枚举对象。 

        对于QVariant类对象表示一个类型可变的值。

QNetworkReply
方法说明
error()获取出错状态
errorString()获取出错原因的字符串描述
readAll()获取响应的body字段
header(QNetworkRequest::knownHeaders header)获取响应头部字段
finished信号当客户端收到一个完整的响应报文只会触发

2.HTTP客户端案例

细节

  • 如何想要显示出来元素的HTML报文,那么就不可以使用QTextEdit控件,因为他会对HTML代码进行渲染,显示出来的就不是原始的HTML报文了,所以需要使用QPlainTextEidt控件。
  • 对于get、post等系列函数只是负责发送请求,不负责请求的等待,所以说他返回的响应对象是一个没有实际内容的对象,那什么时候才收到响应呢?依靠的是finished信号,通过信号槽机制去处理finished信号,也就相当于处理响应了。
#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()
{//获取到输入框中的url,并构建一个url对象QUrl url(ui->lineEdit->text());//构造一个http请求对象QNetworkRequest request(url);//发送get请求,返回一个响应QNetworkReply* response = manager->get(request);//信号槽connect(response, &QNetworkReply::finished, this, [=](){//正确响应了if(response->error() == QNetworkReply::NoError){QString html_data = response->readAll();ui->plainTextEdit->setPlainText(html_data);}else{ui->plainTextEdit->setPlainText(response->errorString());}//释放response对象response->deleteLater();});
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode】--- MySQL刷题集合

1.组合两个表&#xff08;外连接&#xff09; select p.firstName,p.lastName,a.city,a.state from Person p left join Address a on p.personId a.personId; 以左边表为基准&#xff0c;去连接右边的表。取两表的交集和左表的全集 2.第二高的薪水 &#xff08;子查询、if…

【2024年华为OD机试】(B卷,100分)- 数据分类 (Java JS PythonC/C++)

一、问题描述 题目描述 对一个数据a进行分类,分类方法为: 此数据a(四个字节大小)的四个字节相加对一个给定的值b取模,如果得到的结果小于一个给定的值c,则数据a为有效类型,其类型为取模的值;如果得到的结果大于或者等于c,则数据a为无效类型。 比如一个数据a=0x010…

Java 8 实战 书籍知识点散记

一、Lambda表达式 1.1 Lambda表达式的一些基本概念 1.2 Lambda表达式的三个部分 // 简化前Comparator<Apple> byWeightnew Comparator<Apple>() {public int compare(Apple a1, Apple a2){return a1.getWeight().compareTo(a2.getWeight());}};//Lambda表达式Comp…

大数据中 TopK 问题的常用套路

大数据中 TopK 问题的常用套路 作者 Chunel Feng&#xff0c;编程爱好者&#xff0c;阿里巴巴搜索引擎开发工程师。开源项目&#xff1a;Caiss 智能相似搜索引擎 对于海量数据到处理经常会涉及到 topK 问题。在设计数据结构和算法的时候&#xff0c;主要需要考虑的应该是当前算…

GPU算力平台|在GPU算力平台部署MedicalGPT医疗大模型的应用教程

文章目录 一、GPU算力服务平台云端GPU算力平台 二、平台账号注册流程MedicalGPT医疗大模型的部署MedicalGPT医疗大模型概述MedicalGPT部署步骤 一、GPU算力服务平台 云端GPU算力平台 云端GPU算力平台专为GPU加速计算设计&#xff0c;是一个高性能计算中心&#xff0c;广泛应用…

Python - itertools- pairwise函数的详解

前言&#xff1a; 最近在leetcode刷题时用到了重叠对pairwise,这里就讲解一下迭代工具函数pairwise,既介绍给大家&#xff0c;同时也提醒一下自己&#xff0c;这个pairwise其实在刷题中十分有用&#xff0c;相信能帮助到你。 参考官方讲解&#xff1a;itertools --- 为高效循…

DEBERTA:具有解耦注意力机制的解码增强型BERT

摘要 近年来&#xff0c;预训练神经语言模型的进展显著提升了许多自然语言处理&#xff08;NLP&#xff09;任务的性能。本文提出了一种新的模型架构DeBERTa&#xff08;具有解耦注意力机制的解码增强型BERT&#xff09;&#xff0c;通过两种新技术改进了BERT和RoBERTa模型。第…

鸿蒙模块概念和应用启动相关类(HAP、HAR、HSP、AbilityStage、UIAbility、WindowStage、window)

目录 鸿蒙模块概念 HAP entry feature har shared 使用场景 HAP、HAR、HSP介绍 HAP、HAR、HSP开发 应用的启动 AbilityStage UIAbility WindowStage Window 拉起应用到显示到前台流程 鸿蒙模块概念 HAP hap包是手机安装的最小单元&#xff0c;1个app包含一个或…

[OpenGL]实现屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)

一、简介 本文介绍了 屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO) 的基本概念&#xff0c;实现流程和简单的代码实现。实现 SSAO 时使用到了 OpenGL 中的延迟着色 &#xff08;Deferred shading&#xff09;技术。 按照本文代码实现后&#xff0c;可以实现以下…

MATLAB绘图时线段颜色、数据点形状与颜色等设置,介绍

MATLAB在绘图时&#xff0c;设置线段颜色和数据点的形状与颜色是提高图形可读性与美观性的重要手段。本文将详细介绍如何在 MATLAB 中设置这些属性。 文章目录 线段颜色设置单字母颜色表示法RGB 值表示法 数据点的形状与颜色设置设置数据点颜色和形状示例代码 运行结果小结 线段…

AIGC视频生成国产之光:ByteDance的PixelDance模型

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍ByteDance的视频生成模型PixelDance&#xff0c;论文于2023年11月发布&#xff0c;模型上线于2024年9月&#xff0c;同时期上线的模型还有Seaweed&…

mac 电脑上安装adb命令

在Mac下配置android adb命令环境&#xff0c;配置方式如下&#xff1a; 1、下载并安装IDE &#xff08;android studio&#xff09; Android Studio官网下载链接 详细的安装连接请参考 Mac 安装Android studio 2、配置环境 在安装完成之后&#xff0c;将android的adb工具所在…

# [0114] Task01 《数学建模导论》P1 解析几何与方程模型

链接&#xff1a;https://www.datawhale.cn/activity/124 整理的相关代码库 GitHub 页面链接 绪论 姜启源&#xff1a;“数学建模就是建立数学模型解决实际问题” 本质还是解应用题&#xff0c;只是曾经的“小明买糖”变成了如今的“嫦娥探月”。 SEIR 模型&#xff0c;也…

NewStar CTF week1 web wp

谢谢皮蛋 做这题之前需要先去学习一些数据库的知识 1 order by 2 1可以理解为输入的id&#xff0c;是一个占位符&#xff0c;按第二列排序用来测试列数&#xff0c;如果没有两列则会报错-1 union select 1,2 -1同样是占位符&#xff0c;union的作用是将注入语句合并到原始语句…

备赛蓝桥杯之第十五届职业院校组省赛第二题:分享点滴

提示&#xff1a;本篇文章仅仅是作者自己目前在备赛蓝桥杯中&#xff0c;自己学习与刷题的学习笔记&#xff0c;写的不好&#xff0c;欢迎大家批评与建议 由于个别题目代码量与题目量偏大&#xff0c;请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题&#xff0…

C语言初阶牛客网刷题——JZ17 打印从1到最大的n位数【难度:入门】

1.题目描述 牛客网OJ题链接 题目描述&#xff1a; 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 用返回一个整数列表来代替打印n 为正整数&#xff0c;0 < n < 5 示例1 输入&…

PAT甲级-1014 Waiting in Line

题目 题目大意 一个银行有n个窗口&#xff0c;每个窗口最多站m个人&#xff0c;其余人在黄线外等候。假设k个人同时进入银行按先后次序排队&#xff0c;每个人都有相应的服务时间。每个顾客都选择最短队列站&#xff0c;如果有多个相同长度的队列&#xff0c;按序号小的站。给…

LangChain + llamaFactory + Qwen2-7b-VL 构建本地RAG问答系统

单纯仅靠LLM会产生误导性的 “幻觉”&#xff0c;训练数据会过时&#xff0c;处理特定知识时效率不高&#xff0c;缺乏专业领域的深度洞察&#xff0c;同时在推理能力上也有所欠缺。 正是在这样的背景下&#xff0c;检索增强生成技术&#xff08;Retrieval-Augmented Generati…

11 文件与IO

1 File类 1.1 基本介绍 File类代表系统中的文件对象(文件或目录)&#xff0c;位于java.io包下。 存储介质上的文件或目录在Java程序中都是用File类的实例来表示。 通过File类&#xff0c;可以实现对系统中文件或目录的操作&#xff0c;类似我们在操作系统中借助鼠标、快捷键…

Windows第一次上手鸿蒙周边

端云一体所需装备 很重要&#xff1a;C/D/E/F盘要有二三十G的可用空间&#xff01; 硬件&#xff1a;华为鸿蒙实验箱&#xff08;基础版&#xff09;》飞机板核心板环境监测板 软件&#xff1a;Visual Studio Code写代码 终端编译 Hiburn烧录到开发板 MobaXterm &#xff08…