【Qt】系统相关(八)UDP回显客户端的实现,测试,问题思考
前言一、UDP回显客户端的实现二、服务器和客户端的测试三、问题思考微信聊天的原理UDP回显服务器是否可以部署到云服务器上能否使用现在的UDP回显客户端连接之前在Linux阶段编写的UDP服务器
·
小编个人主页详情<—请点击
小编个人gitee代码仓库<—请点击
Qt系列专栏<—请点击
倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己!
目录
前言
【Qt】系统相关(七)网络编程讲解,UDP回显服务器的实现,QUdpSocket和QNetworkDatagram的讲解——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习
本文由小编为大家介绍——【Qt】系统相关(八)UDP回显客户端的实现,测试,问题思考
一、UDP回显客户端的实现
- 在上一篇文章中,小编讲解了UDP相关接口以及UDP回显服务器,本文UDP回显客户端与上一篇文章强相关,所以对上一篇不了解的读者友友务必点击后方蓝字链接进行学习 详情请点击<——

- 为了便于支持我们后续进行服务器和客户端的测试,所以我们需要服务器和客户端的项目代码同时被打开,Qt Creator中是可以同时打开多个项目的,所以在UDP回显服务器对应的UdpServer项目的基础上,所以接下来我们再创建一个项目名为UdpClient,基类为QWidget,派生类为Widget的项目,如上,我们仔细一看,这个样子容易客户端和服务器的项目文件存在同名文件,容易混淆,那么在编写的时候我们要注意区分文件

- 此时问题来了,Qt Creator中有两个项目,如何运行呢?此时我们注意看上面UdpClient项目文件的字体比UdpServer项目的字体要黑,表示此时UdpClient是当前的活动项目,此时我们点击左下角的运行就是运行的UdpClient这个项目,我们如何运行UdpServer呢?所以此时我们右击UdpServer的项目文件,然后可以直接点击运行,此时UdpServer就运行了,同样也可以先点击设置为活动项目,然后再点击屏幕左下角的运行,这两种方式都可以

- 那么对于UDP回显客户端对应的UdpClient项目,UDP回显客户端要支持图形化便于用户操作,应该支持用户进行输入,所以要有一个单行输入框,同样还要给用户提供一个发送按钮,同样还要有一个列表用于显示客户端对应的的请求信息,服务器对应的响应信息,用户在单行输入框中进行输入请求信息,点击发送的按钮之后,类似于微信聊天一样发送了消息此时单行输入框就要被清空
- 点击按钮之后,客户端的请求信息封装成请求报文就要发送给服务器,接下来将客户端的请求信息作为一个元素回显到列表上,服务器收到了来自客户端的请求报文之后,构建好响应报文发送给客户端,客户端收到来自服务器的相应报文之后,将响应报文中的响应信息回显作为一个元素回显到列表上即可,所以对于UDP回显客户端对应的UdpClient项目,接下来我们点击ui文件,进入Qt Designer

- 那么UDP回显客户端应该支持用户进行输入,所以要有一个单行输入框,同样还要给用户提供一个发送按钮,所以此时我们拖拽左侧的QLineEdit单行输入框,QPushButton按钮,然后将按钮显示的文本修改为发送,对于这两个控件,我们鼠标左键按住,选中这两个控件,我们期望这两个控件按列排布,所以就使用水平布局管理器,也就是点击上方红框的水平布局即可

- 接下来我们还要创建一个列表用于显示客户端的请求信息,服务器的响应信息,所以左侧控件我们拖拽一个列表QListWidget,嘶,此时感觉如上这个界面不太均匀,那么我们鼠标左键按住,选中这列表和水平布局管理器中的单行输入框和按钮,我们期望列表和水平布局管理器中的单行输入框和按钮按行排布,所以要使用垂直布局管理器,那么我们点击点击上方红框的垂直布局即可

- 接下来如上图,调整拖拽垂直布局管理器的大小,使之较为均匀的呈现在窗口上,此时还有点不对劲,那么我们仔细观察,垂直布局管理器内部的列表和构成水平管理器的单行输入框和按钮的比例有点不太对,列表占的行比例太大了,我们期望将列表占得行比例小一点,让构成水平布局管理器的单行输入框和按钮占有的行比例大一点,所以我们右上角选中垂直布局管理器QVBoxLayout,然后找到右下角的layoutStretch行拉伸系数,设置为5,1,也就是让垂直布局管理器内部的列表和构成水平管理器的行比例为5比1

- 可是此时我们继续来看,此时虽然垂直布局管理器内部的列表和水平布局管理器的行比例为5比1了,但是水平布局管理器内部的单行输入框和按钮的行占比太窄了,我们期望水平布局管理器内部的单行输入框和按钮的行占比铺满水平布局管理器,也就是要调整垂直策略

- 那么对于水平布局管理器内部的单行输入框和按钮,都是同样的步骤,我们先选中右上角的单行输入框,按钮,然后右下角选择QWidget,然后选择sizePolicy属性,继续展开选择垂直策略,选择垂直策略为Expanding扩展即可

- 如上,所以此时水平布局管理器内部的单行输入框和按钮的行占比就铺满水平布局管理器了,接下来我们右击按钮,然后点击转到槽,接下来我们选择clicked信号,让Qt帮我们生成对应槽函数的声明和定义

- 那么接下来的初步流程和UDP回显器中的一致,由于UDP回显客户端需要使用Qt中网络模块的功能,所以我们在.pro文件中的第一行加入network引入Qt网络模块的功能,然后左下角点击运行,让Qt解析.pro文件的内容,引入Qt网络模块的功能,确保我们后面可以正确包含UDP的相关头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QUdpSocket* socket;
};
#endif // WIDGET_H
- 那么在Widget的.h头文件中,我们包含QUdpSocket对应的头文件#include <QUdpSocket>,为了使用Udp Socket,所以我们同样声明一下QUdpSocket*指针类型的socket
#include "widget.h"
#include "ui_widget.h"
#include <QNetworkDatagram>
const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
socket = new QUdpSocket(this);
this->setWindowTitle("客户端");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
const QString& text = ui->lineEdit->text();
QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);
socket->writeDatagram(requestDatagram);
ui->listWidget->addItem("客户端说: " + text);
ui->lineEdit->setText("");
}
- 接下来在Widget的.cpp源文件中,由于客户端要向服务器发起请求,所以客户端就要知道服务器的IP地址和端口号,那么这里我们就定义一个const修饰的QString&类型的IP地址SERVER_IP ,将IP地址的值设置为127.0.0.1也就是本地环回地址,客户端和服务器在同一台主机上的时候,就可以使用本地环回地址,接下来由于当初我们给UDP服务器绑定的端口号就是9090,我们定义一个const修饰的quint16类型的port端口号SERVER_PORT为9090,这里对于Qt提供的类型quint16我们就要研究一下了
- 端口号port本质上是一个2字节的无符号短整数,1个字节等于8个比特位,也就是说端口号port是16个比特位,所以端口号的返回是0到65535,因此使用Qt提供的类型quint16本质上就是unsigned short,就可用来表示16比特位的port,而Qt为什么要提供内置的quint16呢?其实虽然short通常来讲都是2个字节,但是C++标准库中却没有明确规定这一点,C++标准库中只是规定了short类型的大小不应该少于2字节,所以对于short的大小究竟是多少就不明确了,所以Qt这种框架以及不少的第三方库都使用内置的类型quint16等来明确short的大小为2字节
- 那么在Widget的.cpp源文件中,在Widget的构造函数中,我们就给socket创建实例,也就是new一个QUdpSocket的对象给socket,对于QUdpSocket的构造函数中出现了我们熟悉的parent,也就意味着我们可以传入this指针,指定UDP对应socket的父元素为this指针对应的Widget窗口,将socket对象挂接到对象树上,那么在Widget窗口被关闭销毁的时候,就会自动调用delete去释放socket,对象树机制也可以完美的在Qt网络编程中进行使用,所以这里对于QUdpSocket的构造函数我们传入this指针即可,接下来为了区分客户端和服务器,所以我们使用setWindowTitle将客户端的标题设置为客户端
- 接下来我们就要开始编写发送按钮的clicked点击信号对应的槽函数了,此时用户点击了发送按钮意味着用户此时已经在单行输入框中输入了内容,所以此时我们使用text获取用户在单行输入框内输入的请求信息,然后使用QString类型的text进行保存,此时我们有了要发送的请求信息text了,接下来就要构建请求报文,然后发送给服务器了,下面我们先来构建请求报文,包含好QNetworkDatagram对应的头文件#include <QNetworkDatagram>,然后依次进行传参请求信息text,传参服务器的地址SERVER_IP ,传参服务器的端口号SERVER_PORT

- 那么我们来看对于QNetworkDatagram构造函数的参数类型,首先是第一个参数QByteArray类型,我们传入的参数text是QString类型,所以要使用toUtf8将QString类型转换为QByteArray字节数组类型,对于第二个参数是QHostAddress类型,而我们传入的参数SERVER_IP是QString类型,那么我们QHostAddress可以使用QString类型进行构造,所以这里我们使用QHostAddress(SERVER_IP)构造一个QHostAddress的临时变量进行传参即可,第三个参数port是quint16类型,这里类型匹配,我们不需要进行类型转换
- 此时我们已经构建好了请求报文,接下来我们使用writeDatagram传参请求报文,将请求报文发送给服务器即可,此时就结束了吗?没有,其实我们要实现的是UDP回显客户端,所以对于客户端的请求信息要回显到列表上,所以我们使用字符串客户端说: 拼接上text请求信息作为一个元素添加到列表上即可,此时就结束了吗?没有,类似于微信发送消息之后,我们在输入框中输入的内容要被清空,所以此时我们就使用setText给单行输入框设置一个空串即可
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
void processResponse();
private:
Ui::Widget *ui;
QUdpSocket* socket;
};
#endif // WIDGET_H
- 客户端向服务器发送了请求报文之后,服务器收到并读取请求报文之后,服务器是要基于请求报文,进行业务逻辑的处理,构建出响应报文,将响应报文发送回给客户端的,所以客户端也要具备接收响应报文的能力,也就是说此时客户端也会收到来自服务器的响应报文,进而客户端socket就会触发readyRead信号,进而就要去执行对应的槽函数,所以此时我们有槽函数吗?没有,有进行信号槽的连接吗?没有,所以此时我们在Widget的.h头文件中,声明一个私有的槽函数processResponse
#include "widget.h"
#include "ui_widget.h"
#include <QNetworkDatagram>
const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
socket = new QUdpSocket(this);
this->setWindowTitle("客户端");
connect(socket, &QUdpSocket::readyRead, this, &Widget::processResponse);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
const QString& text = ui->lineEdit->text();
QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);
socket->writeDatagram(requestDatagram);
ui->listWidget->addItem("客户端说: " + text);
ui->lineEdit->setText("");
}
void Widget::processResponse()
{
const QNetworkDatagram& responseDatagram = socket->receiveDatagram();
QString response = responseDatagram.data();
ui->listWidget->addItem("服务器说: " + response);
}
- 接下来在Widget的.cpp源文件中,对于构造函数,此时我们就要使用connect进行socket发出的readyRead信号和this指针对应的Widget中的槽函数processResponse进行连接,此时我们就要来实现一下槽函数processResponse了,此时既然槽函数被执行,那么就意味着readyRead信号被触发,而readyRead信号被触发意味着此时客户端收到了来自服务器的响应报文,所以此时在槽函数processResponse中,我们使用receiveDatagram将来自服务器的响应报文读取上来,并且使用QNetworkDatagram类型的变量responseDatagram进行保存,在responseDatagram这个响应报文中我们使用data拿出有效载荷,也就是服务器的响应信息,保存在QString类型的变量response中
- 这里有一点需要注意,对于responseDatagram我们使用的是QNetworkDatagram的const左值引用类型,而对于response我们使用的是QString的值类型,而对于我们来讲,尤其注意就是该什么时候使用引用类型,什么时候该使用值类型 C++中关于左值引用,const左值引用,右值引用的讲解,详情请点击<——
const QNetworkDatagram& responseDatagram = socket->receiveDatagram();
QString response = responseDatagram.data();
- 以上面为例小编进行讲解,对于responseDatagram我们使用的是QNetworkDatagram的const左值引用类型,receiveDatagram返回的是一个临时变量,我们使用const左值引用进行引用,可以延长这个临时变量的生命周期,此时临时变量的周期就和responseDatagram一样,但是由于是const左值引用,所以不能修改,这里只能进行只读,很明显我们的代码中仅仅是对responseDatagram进行只读,所以这里我们使用const左值引用延长QNetworkDatagram返回的临时变量的生命周期进行只读是没有问题的
- 那么如果我们想要修改引用后的值呢?修改这个临时变量的值,并且还想使用引用的方式该如何做呢?此时就需要使用右值引用了,右值引用是一种夺舍机制,将临时变量的资源直接拿来构造右值引用变量,这个构造的过程中不产生拷贝,开销很小,此时临时变量生命周期不变在这一行代码结束后就会析构,被临时变量构造好的右值引用变量不具有const属性,可读,可修改


- 而对于data的值使用QString进行接收,我们采用的是值类型,这里我们注意到上图data的返回值是QByteArray类型的,这里我们使用QString值类型接收data返回的QByteArray,是进行了不同类型的相互转换,本质上是使用如上右图QString中的构造函数,使用QByteArray构造QString,这个过程中会生成拷贝,开销较大,而要想使用引用的前提就是两边的类型必须要匹配,很明显这里一边是QString类型,一边是QByteArray类型,是无法使用引用的
- 对于引用类型和值类型,大的原则上,肯定是能使用引用就使用引用,因为引用不产生拷贝,可以提升性能,当然这里的提升性能的程度很小很有限,但是对于程序性能的提升总归是有的,但是有的时候像上面的采用QString值类型接收data返回的QByteArray类型,两边类型进行不同类型的转化的时候,这时候由于引用的前提是两边的类型要匹配,所以这里我们无法使用引用类型,只能进行值类型接收,付出拷贝的代价,同样这也是必不可少的
- 此时我们手头已经拿到了服务器发来的响应报文中的有效载荷对应的响应信息response了,由于我们编写的是UDP回显客户端,所以需要将服务器的响应信息也回显到列表上,所以这里我们使用addItem将服务器说: 拼接上响应信息response作为一个元素添加到列表上,也就是将响应数据显示到界面上
- 此时我们的代码编写就已经完成了,下面我们就来进行服务器和客户端的统一测试
二、服务器和客户端的测试

- 对于服务器和客户端的测试,基本原则一定是先启动服务器,然后再启动客户端,因为只有服务器跑起来了之后,服务器才可以提供服务,客户端的请求才有响应,所以此时我们右击服务器项目,然后点击运行,此时服务器就运行起来了,接下来由于客户端项目的字体比服务器黑,所以代表此时客户端是当前的活动项目,那么我们点击屏幕左下角的运行,此时客户端就会运行了
运行结果如下
- 所以此时服务器先运行起来,客户端后运行,此时我们在客户端的单行输入框中输入hello world,然后点击发送,单行输入框的内容就被清空了,此时客户端的列表上就显示了客户端的请求信息hello world
- 此时服务器就可以收到来自客户端的请求报文,接下来服务器基于请求报文中的请求信息构建响应报文,并且将响应报文发送回给客户端,服务器将客户端的IP地址端口号以及请求信息,还有服务器的响应信息拼接成字符串QString作为一个元素回显到列表上
- 客户端收到了来自服务器的响应报文之后,拿到响应报文中的响应信息,将其作为一个元素回显到列表上,同样的小编在客户端的单行输入框输入hello Qt也是同样的原理,这里小编就不再过多解释了
- 那么观察仔细的读者友友可能会看到,服务器上回显的客户端信息的红线冒号后面的IP地址我们认识是127.0.0.1是本地环回,而红线的IP地址我们不认识,那么这是什么呢?其实是IPv6的环回IP,由于我们之前给服务器绑定IP的时候是让监听的所有IP,所以服务器也会对IPv6进行监听,所以这里会有IPv6的本地环回,而127.0.0.1是IPv4的本地环回
- 小编,小编,你这里既然是一个服务器,而服务器是要服务多个客户端的,你这里只让服务器服务了一个客户端,那么我们是否有手段可以启动多个客户端呢?有的有的,那么我们来逐个尝试一下,此时的活动项目是客户端,所以此时如果直接点击左下角的运行,是否可以在原来的客户端保持不变的基础上,新增启动一个客户端呢?
运行结果如下
- 很明显,此时的活动项目是客户端,我们直接点击左下角的运行按钮,此时的情况是结束了原来的客户端,重新运行一个新的客户端,并不能支持我们启动多个客户端
- 好吧,好吧,既然启动都启动了,小编使用这个新的客户端发送一个消息hello C++吧,那么客户端回显了请求与响应信息,服务器也回显了对应客户端的IP地址,端口号,请求与响应信息
- 如上,这里我们可以来看服务器回显的客户端的IP地址和端口号port,对于回显的客户端的IP地址没有什么好说的,这里我们重点关注的是服务器回显的客户端的端口号port
- 很明显服务器回显的这三次客户端的端口号port,而客户端的端口号是当客户端第一个发送请求报文的时候,操作系统随机为客户端绑定的,当随机绑定端口号成功的时候,那么在本次客户端程序运行期间,客户端采用的绑定的端口就是系统本次随机为客户端绑定的,对于这个绑定操作客户端只有一次
- 所以对于我们第一次启动的客户端程序,当客户端程序第一次发送请求报文的时候,系统随机为第一次启动的客户端程序绑定的端口号port是60886,由于绑定操作只有一次,所以后续这个客户端再向服务器发送请求报文的时候,采用的端口号port仍然是60886
- 那么对于第二次,也就是我们点击左下角运行按钮之后,原来第一次启动的客户端程序就被终止了,此时新启动了一个客户端程序,当新启动的这个客户端程序第一次发送请求报文的时候,系统随机为第一次启动的客户端程序绑定的端口号port是53215,很明显与最开始的第一个客户端程序不同
- 那么这里也就印证了前两次向服务器发送请求报文的客户端是同一个客户端,前两次和第三次向服务器发送请求报文的客户端不是同一个客户端
- 小编,小编,既然通过左下角运行按钮的方式不能让我们启动多个客户端程序,那么我们该如何做呢?所以此时我们想要启动多个客户端程序,在之前文章的讲解中,我们知道Qt程序运行是还要有一个bulid临时文件的,在build临时文件中就有可执行程序,此时进行双击就可以启动新的客户端程序了,也就可以满足我们想要启动多个客户端程序的需求了


- 那么此时我们鼠标右击客户端项目中的.pro文件,然后点击在Explorer中显示,此时就会进入上方右图对应的客户端项目的文件目录下,那么此时我们点击上方红框对应的上级目录,也就是返回上级目录


- 此时如上找到bulid对应的UdpClient,双击进入,如上方右图,接下来继续双击进入debug

- 那么在debug文件夹目录中,这里面包含很多客户端程序运行过程中产生的临时文件,其中就包含可执行程序.exe,所以此时双击就可以保持原有客户端程序不变的情况下,继续启动一个新的客户端程序
运行结果如下
- 此时我们双击.exe可执行程序,那么此时就启动了一个新的客户端程序,并且小编使用这个新的客户端发送一个消息aaaaa,那么新的客户端回显了请求与响应信息,服务器也回显了对应客户端的IP地址,端口号,请求与响应信息,没有问题
- 那么此时我们原来运行的那一个客户端能否运行呢?所以小编使用原有的客户端发送一个消息bbbbb,那么原有的客户端回显了请求与响应信息,服务器也回显了对应客户端的IP地址,端口号,请求与响应信息,没有问题
- 接下来小编继续双击.exe可执行程序,那么此时就又启动了第二个新的客户端程序,此时共计三个客户端了,并且小编使用第二个新的客户端发送一个消息ccccc,那么第二个新的客户端回显了请求与响应信息,服务器也回显了对应客户端的IP地址,端口号,请求与响应信息,没有问题
4. 如上,通过这里的服务器上打印了关于客户端的端口号port就可以区分出这三个客户端是不同的客户端,也就意味着此时我们启动了多个客户端成功,服务器可以同时处理多个客户端的请求
三、问题思考
微信聊天的原理
- 所以此时基于我们编写的UDP回显服务器的实现,UDP回显客户端的实现,我们其实已经可以看出这就是超级mini版的微信,并且我们也可以从我们的运行结果中,窥探一些微信运行的原理,虽然我们的UDP回显客户端是通过本地环回连接的UDP回显服务器,那么是否我们可以把这个UDP回显服务器部署到其它的主机上提供服务呢?
- 毫无疑问,肯定是可以的,那么此时我在我的主机上配置好UDP回显服务器的主机的IP地址和端口号UDP,此时就通过回显客户端连接部署在其它主机上的UDP回显服务器,同样的我的朋友可以在自己的主机上配置好UDP回显服务器的主机的IP地址和端口号UDP,同样可以就通过回显客户端连接部署在其它主机上的UDP回显服务器
- 所以此时我想要给我的朋友发送消息,此时消息就要先发送给了服务器,服务器只需要将这个消息发送给我朋友的客户端上即可,同样的我朋友收到我的消息之后,回复我的消息,那么此时同样的,我朋友的消息也要先发送给服务器,服务器再把这个消息发送给我即可,此时我就收到了来自朋友的回复,此时我和我的朋友就跨主机进行通信了,此时和我的朋友聊天就实现了
- 同样的对于一个群聊来讲,当有人在群聊中发送消息的时候,同样的这个消息也要先发送给服务器,服务器再将这个消息同步发送到处于这个群聊的每一个人的主机上,此时处于这个群聊的每一个都看到了这个人在群聊中发送的消息了,此时有另外一个人对这个消息进行回复,同样的这个消息也要先发送给服务器,服务器再将这个消息同步发送到处于这个群聊的每一个人的主机上,此时处于这个群聊的每一个都看到了另一个人对于这个人消息的回复了,此时群聊功能就实现了,即微信聊天的原理我们此时也理解了
UDP回显服务器是否可以部署到云服务器上
- 我们之前在学习Linux网络编程的时候 关于Linux网络编程的讲解,详情请点击<——,使用的是云服务器部署服务器程序,并且使用客户端程序可以进行连接服务器程序

- 那么我们能否把现在的UDP回显服务器部署到云服务器上呢?那么大概率是不行的,这取决于我们的云服务器是否安装了图形化界面,Qt程序,本身是依赖于图形化界面运行的,如上我们在.pro文件中引入了gui模块,这个gui模块的引入需要运行的平台上有图形化界面的支撑,而很明显之前我们搞的Linux云服务器,一般都是没有图形化界面的,如果想要使用图形化界面,需要进行额外的手动安装,所以大概率是不能将现在的UDP回显服务器部署到云服务器上
- 同样的我们也要认识到,而图形化界面的显示势必会带来性能上的消耗,一定程度上减少服务的客户端,所以对于服务器程序,为了性能,为了服务更多的客户端来讲,作为一个服务器,正常来讲,本身就不应该有图形化界面,而我们这里编写的UDP回显服务器中给服务器引入了图形化界面,目的是为了便于演示Qt网络编程的情况,便于我们观察现象,而Qt本身是依赖图形化界面运行的,所以对于服务器程序来讲,服务程序的编写不会采用Qt进行编写
能否使用现在的UDP回显客户端连接之前在Linux阶段编写的UDP服务器
- 那么还有一个问题,能否使用现在的UDP回显客户端连接之前在Linux阶段编写的UDP服务器?注意,Linux阶段编写的UDP服务器是没有图形化界面的,而我们这里的UDP回显客户端是有图形化界面的,所以能否使用现在的UDP回显客户端连接之前在Linux阶段编写的UDP服务器呢?其实是可以的,完全没问题的,为什么呢?
- 因为虽然Linux阶段编写的UDP服务器是没有图形化界面,但是Linux阶段编写的UDP服务器本身是采用的UDP协议进行通信的,而我们这里的UDP回显客户端虽然有图形化界面,但是同样的我们这里的UDP回显客户端也是采用UDP协议进行通信的,你服务器采用的是UDP协议,我客户端采用的是UDP协议,协议相同,双方达成的约定相同,那么客户端的UDP请求报文就可以服务器解析,服务器的UDP响应报文自然同样可以被客户端解析,所以网络编程中采用的协议都是相同的协议,即使一个没有图形化界面,一个有图形化界面,只要网络编程中采用的协议都是相同的协议,这里是采用的相同的UDP协议,都是可以进行连接,进行通信的,进行交互的
- 同样的,你UDP服务器是采用C++写的,我UDP客户端是采用Qt写的,采用Java写的,采用Python写的,那么是否可以进行客户端和服务器的连接,进行通信呢?可以的,一定可以,因为服务器采用的网络协议是UDP协议,客户端采用的是UDP协议,虽然语言不同,但是大家采用的网络协议都是UDP协议,自然的采用的协议相同,双方达成的约定相同,那么客户端的UDP请求报文就可以服务器解析,服务器的UDP响应报文自然同样可以被客户端解析,这也是网络编程,协议的意义所在
- 这里我们要认识到,一般商业公司的项目,都是通过其它方式编写的服务器程序,大概率不会采用Qt编写服务器程序,但是可以使用Qt编写客户端程序,所以只要服务器和客户端采用的网络协议相同,那么就可以正常进行请求报文,响应报文的解析,自然的其它方式编写的服务器和Qt编写的客户端程序也就可以正常进行连接,报文解析,交流,交互
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助
水滴石穿,坚持就是胜利,读者朋友们可以点个关注
点赞收藏加关注,找到小编不迷路!
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐










所有评论(0)