当前位置: 首页 > backend >正文

Qt中UDP回显服务器和客户端

Qt中UDP回显服务器和客户端

在进⾏⽹络编程之前, 需要在项⽬中的 .pro ⽂件中添加 network 模块.

添加之后要⼿动编译⼀下项⽬, 使 Qt Creator 能够加载对应模块的头⽂件

UDP Socket

核⼼ API 概览

主要的类有两个. QUdpSocket 和 QNetworkDatagram

QUdpSocket 表⽰⼀个 UDP 的 socket ⽂件.
在这里插入图片描述

QNetworkDatagram 表⽰⼀个 UDP 数据报.
在这里插入图片描述

回显服务器

  1. 创建界⾯, 包含⼀个 QListWidget ⽤来显⽰消息.

在这里插入图片描述

  1. 创建 QUdpSocket 成员

修改 widget.h

#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 processResponse();
private:Ui::Widget *ui;QUdpSocket*socket;
};
#endif // WIDGET_H

修改 widget.cpp, 完成 socket 后续的初始化

⼀般来说, 要先连接信号槽, 再绑定端⼝.

如果顺序反过来, 可能会出现端⼝绑定好了之后, 请求就过来了. 此时还没来得及连接信号槽. 那么这个请求就有可能错过了

#include <QMessageBox>
#include <QNetworkDatagram>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::processRequest);//绑定端口号bool ret=socket->bind(QHostAddress::Any,9090);if(!ret){//绑定失败QMessageBox::critical(this,"服务器启动出错",socket->errorString());return;}
}
  1. 实现 processRequest , 完成处理请求的过程

• 读取请求并解析

• 根据请求计算响应

• 把响应写回到客⼾端

//服务器最核心的逻辑
void Widget::processRequest()
{//1.读取请求分析const QNetworkDatagram& requestDatagram=socket->receiveDatagram();QString request=requestDatagram.data();//2.根据请求计算响应const QString& response=process(request);//3.把响应写道客户端QNetworkDatagram responseDatagram(response.toUtf8(),requestDatagram.senderAddress(),requestDatagram.senderPort());socket->writeDatagram(responseDatagram);//把这个信息显示交互到页面上QString log="["+requestDatagram.senderAddress().toString()+":"+QString::number(requestDatagram.senderPort())+"]req:"+request+",resp:"+response;ui->listWidget->addItem(log);
}
  1. 实现 process 函数
QString Widget::process(const QString &request)
{return request;
}

💡 “根据请求处理响应” 是服务器开发中的最核⼼的步骤.

⼀个商业服务器程序, 这⾥的逻辑可能是⼏万⾏⼏⼗万⾏代码量级的

此时, 服务器程序编写完毕.

但是直接运⾏还看不出效果. 还需要搭配客⼾端来使⽤.

回显客⼾端

  1. 创建界⾯. 包含⼀个 QLineEdit , QPushButton , QListWidget

• 先使⽤⽔平布局把 QLineEdit 和 QPushButton 放好, 并设置这两个控件的垂直⽅向的sizePolicy 为 Expanding

• 再使⽤垂直布局把 QListWidget 和上⾯的⽔平布局放好.

• 设置垂直布局的 layoutStretch 为 5, 1 (当然这个尺⼨⽐例根据个⼈喜好微调).

在这里插入图片描述

  1. 在 widget.cpp 中, 先创建两个全局常量, 表⽰服务器的 IP 和 端⼝
//定义两个常量,表示服务器的地址和端口号
const QString&SERVER_IP="127.0.0.1";
const quint16 SERVER_PORT=9090;
  1. 创建 QUdpSocket 成员

修改 widget.h, 定义成员

#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 processResponse();
private:Ui::Widget *ui;QUdpSocket*socket;
};
#endif // WIDGET_H

修改 widget.cpp, 初始化 socket

#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 processResponse();
private:Ui::Widget *ui;QUdpSocket*socket;
};
#endif // WIDGET_H
  1. 给发送按钮 slot 函数, 实现发送请求.
void Widget::on_pushButton_clicked()
{//获取到输入框的内容const QString& text=ui->lineEdit->text();//构造UDP的请求数据QNetworkDatagram requestDatagram(text.toUtf8(),QHostAddress(SERVER_IP),SERVER_PORT);//发送请求数据socket->writeDatagram(requestDatagram);//把发送的数据添加到列表框ui->listWidget->addItem("客户端说:"+text);//把输入框的内容清空一下ui->lineEdit->setText("");
}
  1. 再次修改 Widget 的构造函数, 通过信号槽, 来处理服务器的响应.
 	//通过信号槽来处理,来处理服务器返回的数据connect(socket,&QUdpSocket::readyRead,this,&Widget::processResponse);void Widget::processResponse()
{//通过这个函数来处理收到的响应//1.读取到响应数据const QNetworkDatagram& responseDatagram=socket->receiveDatagram();QString response=responseDatagram.data();//2.把响应数据显示到界面上ui->listWidget->addItem("服务器说:"+response);
}
http://www.xdnf.cn/news/19374.html

相关文章:

  • 第二十七天-ADC模数转换实验
  • python反转字符串
  • 三维重建模型、3DGS、nerf、 mip-nerf
  • 《WINDOWS 环境下32位汇编语言程序设计》第9章 通用控件(2)
  • 点接触混合润滑完整数值解
  • 免税商品优选购物商城系统|java技术开发
  • MATLAB R2010b系统环境(三)MATLAB操作界面
  • JavaWeb01
  • 【Linux】创建线程
  • 基于K8s部署Redis高可用
  • mit6.031软件构造 笔记 Testing
  • Redis进阶(上)
  • Win11输入法异常解决方案
  • 智能合约安全全解析:常见漏洞、真实案例与防范实践
  • 机器视觉学习-day14-绘制图像轮廓
  • 【机器学习基础】监督学习算法的现代理解:从经典方法到无人驾驶与生成式AI的实践应用
  • [光学原理与应用-353]:ZEMAX - 设置 - 可视化工具:2D视图、3D视图、实体模型三者的区别,以及如何设置光线的数量
  • 财务的三张报表:现金流表、利润表、资产负债表
  • Spring/Spring MVC/iBATIS 应用 HTTP 到 HTTPS 迁移技术方案
  • 基于i.MX6ULL的RAM Disk驱动开发
  • 【开题答辩全过程】以 付费自习室系统小程序为例,包含答辩的问题和答案
  • 【编号186】中国劳动统计年鉴(1991-2023)
  • kafka服务端架构总览
  • 【C++】显示与隐式加载dll的使用与区别
  • 技术框架之RPC
  • 【系统分析师】高分论文:论信息系统的安全与保密设计
  • c++ 线程局部存储(Thread-Local Storage,TLS)
  • 当服务器报警响起:CPU、内存、磁盘使用率飙升的诊断与处置
  • 基于单片机智能鞋柜/智能鞋橱/智能鞋盒
  • C++项目的Makefile案例解析