FPGA - 以太网UDP通信(一)

一,简述以太网

以太网简介

​以太网是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以太网的技术标准,它规定了包括物理层的连线、电子信号和介质访问层协议的内容。 ​

以太网类型介绍

以太网是现实世界中最普遍的一种计算机网络。以太网有两类:第一类是经典以太网,第二类是交换式以太网,使用了一种称为交换机的设备连接不同的计算机。经典以太网是以太网的原始形式,运行速度从3~10 Mbps不等;而交换式以太网正是广泛应用的以太网,可运行在100、1000和10000Mbps那样的高速率,分别以快速以太网、千兆以太网和万兆以太网的形式呈现。

二,OSI七层模型和TCP/IP五层模型

OSI模型,即开放式通信系统互联参考模型Open System Interconnection Reference Model),是国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。”

OSI七层模型

OSI定义了网络互连的七层模型(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层),如下图所示:

应用层:为应用程序或用户请求提供各种请求服务。OSI参考模型最高层,也是最靠近用户的一层,为计算机用户、各种应用程序以及网络提供接口,也为用户直接提供各种网络服务。

表示层:数据编码、格式转换、数据加密。提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要,该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的转换功能之一。

会话层:创建、管理和维护会话。接收来自传输层的数据,负责建立、管理和终止表示层实体之间的通信会话,支持它们之间的数据交换。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。

传输层:数据通信。建立主机端到端的链接,为会话层和网络层提供端到端可靠的和透明的数据传输服务,确保数据能完整的传输到网络层。

网络层:IP选址及路由选择。通过路由选择算法,为报文或通信子网选择最适当的路径。控制数据链路层与传输层之间的信息转发,建立、维持和终止网络的连接。数据链路层的数据在这一层被转换为数据包,然后通过路径选择、分段组合、顺序、进/出路由等控制,将信息从一个网络设备传送到另一个网络设备。

数据链路层:提供介质访问和链路管理。接收来自物理层的位流形式的数据,封装成帧,传送到网络层;将网络层的数据帧,拆装为位流形式的数据转发到物理层;负责建立和管理节点间的链路,通过各种控制协议,将有差错的物理信道变为无差错的、能可靠传输数据帧的数据链路。

物理层:管理通信设备和网络媒体之间的互联互通。传输介质为数据链路层提供物理连接,实现比特流的透明传输。实现相邻计算机节点之间比特流的透明传送,屏蔽具体传输介质和物理设备的差异。

TCP/IP五层模型

TCP/IP是一组协议的代名词,它包括许多协议,组成了TCP/IP协议簇。它是把OSI七层模型简化成了五层模型。每一层都呼叫它的下一层所提供的网络来完成自己的需求

TCP/IP 五层协议和 OSI 的七层协议对应关系如下:

从上图中可以看出, TCP/IP 模型⽐ OSI 模型更加简洁,它把 应⽤层/表示层/会话层 全部整合为了 应⽤层

在每⼀层都⼯作着不同的设备,⽐如我们常⽤的交换机就⼯作在数据链路层的,⼀般的路由器是⼯作在⽹络层的。

在每⼀层实现的协议也各不同,即每⼀层的服务也不同,下图列出了每层主要的传输协议:

一般说的FPGA UDP通信,FPGA只做到了传输层,传输层以上的会话层、表示层等等,FPGA是没有的。FPGA 开发板通过一片 以太网PHY芯片 提供对以太网连接的支持,PHY芯片内提供物理层,进行4b/10b编码,PHY芯片提供MII/GMII/RGMII 接口的MAC连接

在传输层中 TCPUDP都是传输层协议,它们都属于TCP/IP协议族:

🤔 UDP

UDP的全称是⽤户数据报协议,在⽹络中它与TCP协议⼀样⽤于处理数据包,是⼀种⽆连接的协议。在OSI模型中,在传输层,处于IP协议的上⼀层。UDP有 不提供数据包分组、组装和不能对数据包进⾏排序的缺点,也就是说,当报⽂发送之后,是⽆法得知其是否安全完整到达的

它的特点如下:

  1. 面向无连接
  2. 有单播、多播、广播的功能
  3. 面向报文
  4. 不可靠性
  5. 头部开销⼩,传输数据报⽂⾼效。
🧐 TCP
  1. 面向连接
  2. 仅支持单播传输
  3. 面向字节流
  4. 可靠传输
  5. 提供拥塞控制
  6. 提供全双工通信
😜 TCP和UDP的区别

三,FPGA UDP通信硬件构成

        根据以上的简述,我们知道 FPGA UDP通信 FPGA只做到了传输层,传输层以上的会话层、表示层等等,FPGA是没有的。 所以PC端发送数据经过传输层添加TCP/UDP 头部后,在经过网络层添加IP头部,然后经过数据链路层添加MAC头部,通过层级组包传输到FPGA的PHY芯片内提供物理层,进行4b/10b编码,PHY芯片提供MII/GMII/RGMII 接口的MAC连接

硬件简化图如下所示:

组包简化图如下所示:

 四,PHY芯片接口介绍

从数据传输角度来看,控制器(FPGA )PHY 侧芯片实现以太网传输的数据链路两端,有 3 种主要的接口形式。这 3 种接口形式主要是 MII GMIIRGMII 。 MII 主要应用在百兆网传输中,而 GMII 和 RGMII 则均可以运用于千兆网, RGMII 相较于 GMII ,则可以有更高的数据位通信效率。

MII 接口

MII 接口信号连接关系及各信号的介绍如下。

GMII 接口

GMII 接口信号连接关系及各信号的介绍如下。

GMII 发送和接收时序:

RGMII 接口

RGMII 即ReducedGMII,是GMII 的简化版本,将接口信号线数量从24根减少到14根,时钟频率仍旧为125MHz,TX/RX 数据宽度从8 位变为4位。RGMII接口信号连接关系及各信号的介绍如下。

RGMII接口为了保持1000Mbps 的传输速率不变, RGMII 接口在时钟的上升沿和下降沿都采样数据。在参考时钟的上升沿发送 GMII 接口中的 TXD[3:0]/RXD[3:0] ,在参考时钟的下降沿发送 GMII 接口中的 TXD[7:4]/RXD[7:4] 。

RGMII 的时序分为两种:延时模式和非延时模式,可以通过配置PHY芯片改变模式。 用的比较多的模式是延时模式,一般PHY芯片默认配置为延时模式

时序图如下:

根据以上介绍,我们使用RGMII接口的以太网 PHY 与 MAC (PHY )的连接实现方法,解决了接口问题,才能编写对应的网络协议实现逻辑。

五,RGMII和GMII转换电路设计

在以上了解中,我们知道RGMII 是GMII 的简化版本,接口信号线数量从24根减少到14根,TX/RX 数据宽度从8 位变为4位,所以我们要实现RGMII的发送与接收

RGMII发送

对于FPGA来说,实现 RGMII 接口的发送是一个非常直接的过程,整个发送逻辑框图如图所示:

设计实现时,我们需要使用xilinx 的ODDR(Output Double Data Rate,输出双倍数据速率)原语,将该接口使用OLOGIC 块实现。ODDR 原语只有一个时钟输入,下降沿数据由输入时钟的本地反转来计时,反馈到I/O块的所有的时钟被完全复用,ODDR 原语的框图如图 所示:

其中各个端口的功能及描述如下:

除了这些端口外, ODDR原语还包含一些可用属性:

编写rgmii_send代码:

module rgmii_send(input                reset              ,output               phy_rgmii_tx_clk  ,output               phy_rgmii_tx_ctl  ,output [3:0]         phy_rgmii_tx_data ,input                gmii_tx_clk       ,input                gmii_tx_vld       ,input [7:0]          gmii_tx_data      );wire			rgmii_tx_ctl;
wire	[3:0]	rgmii_tx_data;     /*------------------------------------------*\ODDR
\*------------------------------------------*/ODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT(1'b0),    // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) oddr_tx_rgmii_ctl (.Q(rgmii_tx_ctl),   // 1-bit DDR output.C(gmii_tx_clk),   // 1-bit clock input.CE(1), // 1-bit clock enable input.D1(gmii_tx_vld), // 1-bit data input (positive edge).D2(gmii_tx_vld), // 1-bit data input (negative edge).R(0),   // 1-bit reset.S(0)    // 1-bit set);genvar i_tx;
generatefor ( i_tx = 0; i_tx < 4; i_tx = i_tx + 1) beginODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT(1'b0),    // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) oddr_tx_rgmii_ctl (.Q(rgmii_tx_data[i_tx]),   // 1-bit DDR output.C(gmii_tx_clk),   // 1-bit clock input.CE(1), // 1-bit clock enable input.D1(gmii_tx_data[i_tx]), // 1-bit data input (positive edge).D2(gmii_tx_data[i_tx + 4]), // 1-bit data input (negative edge).R(0),   // 1-bit reset.S(0)    // 1-bit set);end
endgenerate/*------------------------------------------*\OBUF
\*------------------------------------------*/OBUF  obuf_tx_rgmii_clk(.O(phy_rgmii_tx_clk),     // Buffer output (connect directly to top-level port).I(gmii_tx_clk)      // Buffer input);OBUF  obuf_tx_rgmii_ctl(.O(phy_rgmii_tx_ctl),     // Buffer output (connect directly to top-level port).I(rgmii_tx_ctl)      // Buffer input);genvar j_tx;
generatefor ( j_tx = 0; j_tx < 4; j_tx = j_tx + 1) beginOBUF  obuf_tx_rgmii_data(.O(phy_rgmii_tx_data[j_tx]),     // Buffer output (connect directly to top-level port).I(rgmii_tx_data[j_tx])      // Buffer input);	end
endgenerate
endmodule

RGMII接收

对于 FPGA 来说,实现 RGMII 接口的接收同样是一个非常直接的过程, 整个接收逻辑框图如图所示:

同样,设计实现时,可通过使用xilinx 的IDDR 原语,将该接口使用ILOGIC 块实现。在ILOGIC 块中,有着专用的寄存器,用于实现输入双倍数据速率(DDR)寄存器,当我们实例化IDDR 原语时便会自动访问该功能。IDDR 原语的框图如图所示:

其中各个端口的功能及描述如表

除了这些端口外, IDDR 原语还包含一些可用属性:

编写rgmii_receive代码:

`timescale 1ns / 1ps
module rgmii_receive(input				reset 				,input 				delay_refclk		,input 				phy_rgmii_rx_clk 	,input 				phy_rgmii_rx_ctl 	,input [3:0]			phy_rgmii_rx_data 	,output 				gmii_rx_clk			,output				gmii_rx_vld			,output				gmii_rx_error		,	output [7:0]		gmii_rx_data 			);wire			phy_rgmii_rx_clk_ibuf;	wire			phy_rgmii_rx_ctl_ibuf;wire	[3:0]	phy_rgmii_rx_data_ibuf;// wire            phy_rgmii_rx_ctl_delay;// wire [3:0]      phy_rgmii_rx_data_delay;wire 			gmii_rx_error_xor	 	;	assign gmii_rx_error = gmii_rx_vld ^ gmii_rx_error_xor;// assign gmii_rx_clk = phy_rgmii_rx_clk;/*------------------------------------------*\IBUF\*------------------------------------------*/IBUF rgmii_rx_clk_ibuf (.O(phy_rgmii_rx_clk_ibuf),     // Buffer output.I(phy_rgmii_rx_clk)      // Buffer input (connect directly to top-level port));IBUF rgmii_rx_ctl_ibuf (.O(phy_rgmii_rx_ctl_ibuf),     // Buffer output.I(phy_rgmii_rx_ctl)      // Buffer input (connect directly to top-level port));genvar i_rx;generatefor ( i_rx = 0; i_rx < 4; i_rx = i_rx + 1) beginIBUF rgmii_rx_data_ibuf (.O(phy_rgmii_rx_data_ibuf[i_rx]),     // Buffer output.I(phy_rgmii_rx_data[i_rx])      // Buffer input (connect directly to top-level port));endendgenerate/*------------------------------------------*\BUFG 、BUFIO\*------------------------------------------*/BUFG rgmii_rx_clk_bufg (.O(gmii_rx_clk), // 1-bit output: Clock output.I(phy_rgmii_rx_clk_ibuf)  // 1-bit input: Clock input);// BUFIO rgmii_rx_clk_bufio (//    .O(phy_rgmii_rx_clk_bufio), // 1-bit output: Clock output (connect to I/O clock loads).//    .I(phy_rgmii_rx_clk)  // 1-bit input: Clock input (connect to an IBUF or BUFMR).// );/*-----------------------------------------*\IDDR\*-----------------------------------------*/IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // "OPPOSITE_EDGE", "SAME_EDGE" //    or "SAME_EDGE_PIPELINED" .INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) iddr_rgmii_rx_ctl (.Q1(gmii_rx_vld), // 1-bit output for positive edge of clock.Q2(gmii_rx_error_xor), // 1-bit output for negative edge of clock.C(phy_rgmii_rx_clk_ibuf),   // 1-bit clock input.CE(1), // 1-bit clock enable input.D(phy_rgmii_rx_ctl_ibuf),   // 1-bit DDR data input.R(0),   // 1-bit reset.S(0)    // 1-bit set);genvar q_rx;generatefor (q_rx = 0; q_rx<4 ; q_rx = q_rx+ 1) beginIDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // "OPPOSITE_EDGE", "SAME_EDGE" //    or "SAME_EDGE_PIPELINED" .INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) iddr_rgmii_rx_data (.Q1(gmii_rx_data[q_rx]), // 1-bit output for positive edge of clock.Q2(gmii_rx_data[q_rx + 4]), // 1-bit output for negative edge of clock.C(phy_rgmii_rx_clk_ibuf),   // 1-bit clock input.CE(1), // 1-bit clock enable input.D(phy_rgmii_rx_data_ibuf[q_rx]),   // 1-bit DDR data input.R(0),   // 1-bit reset.S(0)    // 1-bit set);endendgenerateendmodule

RGMII 顶层

RGMII 接口分别实现了接收和发送两部分,将两部分例化封装顶层rgmii_interface

module rgmii_interface(input               reset             ,input               delay_refclk      ,input               phy_rgmii_rx_clk  ,input               phy_rgmii_rx_ctl ,input [3:0]         phy_rgmii_rx_data ,output              gmii_rx_clk       ,output              gmii_rx_vld       ,output              gmii_rx_error     ,output [7:0]        gmii_rx_data      ,output              phy_rgmii_tx_clk  ,output              phy_rgmii_tx_ctl  ,output [3:0]        phy_rgmii_tx_data ,input               gmii_tx_clk       ,input               gmii_tx_vld       ,input [7:0]         gmii_tx_data );rgmii_receive rgmii_receive(.reset             (reset),.delay_refclk      (delay_refclk),.phy_rgmii_rx_clk  (phy_rgmii_rx_clk),.phy_rgmii_rx_ctl (phy_rgmii_rx_ctl),.phy_rgmii_rx_data (phy_rgmii_rx_data),.gmii_rx_clk       (gmii_rx_clk),.gmii_rx_vld       (gmii_rx_vld),.gmii_rx_error     (gmii_rx_error),.gmii_rx_data      (gmii_rx_data));rgmii_send rgmii_send(.reset             (reset),.phy_rgmii_tx_clk  (phy_rgmii_tx_clk),.phy_rgmii_tx_ctl  (phy_rgmii_tx_ctl),.phy_rgmii_tx_data (phy_rgmii_tx_data),.gmii_tx_clk       (gmii_tx_clk),.gmii_tx_vld       (gmii_tx_vld),.gmii_tx_data      (gmii_tx_data));endmodule

六,总结

至此,关于FPGA UDP通信的RGMII 接口与 GMII 接口的互转逻辑设计已经实现,在 FPGA 中设计以太网的接收和发送逻辑时,只需要按照 GMII 接口的形式,先设计出对应的发送和接收逻辑,再将对应的端口连接到 RGMII 与 GMII 接口转换逻辑上,就能够完成基于 RGMII 接口的以太网接收和发送。

接下来,在下一篇博客中将会实现数据链路层(mac层)的接收与发送。

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

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

相关文章

[C++][算法基础]二分图的最大匹配(匈牙利算法)

给定一个二分图&#xff0c;其中左半部包含 n1 个点&#xff08;编号 1∼n1&#xff09;&#xff0c;右半部包含 n2 个点&#xff08;编号 1∼n2&#xff09;&#xff0c;二分图共包含 m 条边。 数据保证任意一条边的两个端点都不可能在同一部分中。 请你求出二分图的最大匹配…

Intel显卡驱动导致Qt opengl 渲染YUV时拉伸窗口内存泄漏

最近在使用QOpenGLWidget做YUV视频渲染&#xff0c;发现在拉伸窗口的时候内存暴涨&#xff0c;如果窗口不动则内存不变。 可以得出结论一定是resizeGL出了问题&#xff0c;但是其实这里代码很简单 glViewport(0, 0, w, h); 还有就是变换矩阵计算&#xff0c;根本没资源建立与释…

Sublime Text下载,安装,安装插件管理器,下载汉化插件

SublimeTest官网 © Sublime Text中文网 下载安装 一路点击安装即可 安装插件管理器 管理器官网安装 - 包控制 (packagecontrol.io) 手动安装将3 位置点击网址下载 再打开SublimeTest 点击 选择第一个Browse Packages..... 将会跳转到文件夹中 进入上一个文件夹 在进入…

【读点论文】YOLOX: Exceeding YOLO Series in 2021,无锚框单阶段目标检测方案,解耦检测头的分类和回归分支,优化标签分配策略

YOLOX: Exceeding YOLO Series in 2021 Abstract 在本报告中&#xff0c;我们介绍了YOLO系列的一些经验改进&#xff0c;形成了一种新的高性能探测器—YOLOX。我们将YOLO检测器切换到无锚方式&#xff0c;并进行其他先进的检测技术&#xff0c;即去耦头和领先的标签分配策略S…

4月16号总结

java学习 网络编程 1.网络分层 网络分层是将网络通信划分为不同的逻辑层次&#xff0c;每一层负责特定的功能&#xff0c;从而实现网络通信的模块化和标准化。常用的网络分层模型包括OSI&#xff08;开放系统互联&#xff09;模型和TCP/IP模型。 特点和作用&#xff1a; 分…

origin绘图操作合集

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、图例去掉边框二、柱状图单独选中某一柱子修改颜色&#xff0c;柱状图中设置一个柱子的方法 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参…

Java开发从入门到精通(二十):Java的面向对象编程OOP:IO流中的转换流、打印流、数据流、序列流、IO框架

Java大数据开发和安全开发 &#xff08;一&#xff09;Java的IO流文件读写1.1 转换流1.1.1 InputStreamReader字符输入转换流1.1.1 OutputStreamWriter字符输出转换流 1.2 打印流1.2.1 PrintStream打印流1.2.2 PrintWriter打印流1.2.3 PrintStream和PrintWriter的区别1.2.4 打印…

获取淘宝京东商品详情API接口返回数据解析说明(可测试,批量获取)

获取淘宝和京东的商品详情API接口返回数据并解析通常需要遵循以下几个步骤&#xff1a; 淘宝商品详情API 淘宝的API接口通常对商家和合作伙伴开放&#xff0c;并且需要经过严格的申请和审核流程。普通用户或未经授权的开发者通常无法直接访问淘宝的商品详情API。 如果你已经…

Innodb之redo日志

Innodb引擎执行流程 redo log ​ MySQL中的redo log&#xff08;重做日志&#xff09;是实现WAL&#xff08;预写式日志&#xff09;技术的关键组件&#xff0c;用于确保事务的持久性和数据库的crash-safe能力。借用《孔乙己》中酒店掌柜使用粉板记录赊账的故事&#xff0c;…

2024.4.16

三个按键的中断 do_irq.c #include "mykey.h" extern void printf(const char *fmt, ...); unsigned int i 0; void do_irq(void) {//获取中断号unsigned int irqno (GICC->IAR&0x3ff);switch (irqno){case 99://中断处理逻辑printf("KEY1_INTC\n&q…

jenkins构建微信小程序并展示二维码

测试小程序的过程中&#xff0c;很多都是在回头和前端开发说一句&#xff0c;兄弟帮我打一个测试版本的测试码&#xff0c;开发有时间的情况下还好&#xff0c;就直接协助了&#xff0c;但是很多时候他们只修复了其中几个bug&#xff0c;其他需要修复的bug代码正在编写&#xf…

健身管理小程序|基于微信开发健身管理小程序的系统设计与实现(源码+数据库+文档)

健身管理小程序目录 基于微信开发健身管理小程序设计与实现 一、前言 二、系统设计 三、系统功能设计 小程序端&#xff1a; 后台 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码…

策略模式(知识点)——设计模式学习笔记

文章目录 0 概念1 使用场景2 优缺点2.1 优点2.2 缺点 3 实现方式4 和其他模式的区别5 具体例子实现5.1 实现代码 0 概念 定义&#xff1a;定义一个算法族&#xff0c;并分别封装起来。策略让算法的变化独立于它的客户&#xff08;这样就可在不修改上下文代码或其他策略的情况下…

前端三件套学习笔记(持更)

HTML CSS 1、HTML&#xff0c;CSS&#xff0c;JS区别 HTML--结构 CSS--表现 JavaScript--行为 2、HTML5 中新增 1&#xff09;语义化标签 <header>、<main>页面主要内容、<aside>侧边栏、<footer>、<nav>、<article> 加载页面一块…

Redis 缓存预热、预热数据选取策略、缓存保温、性能边界

缓存预热 热点数据预热&#xff1a;根据业务分析或统计数据&#xff0c;确定热点数据&#xff08;经常被访问的数据&#xff09;&#xff0c;并将其提前加载到Redis缓存中。可以根据访问频率、访问量或其他业务指标来确定热点数据。定时预热&#xff1a;可以设置定时任务&…

QT 串口助手 学习制作记录

QT 串口助手qt 学习制作记录 参考教程&#xff1a;​​​​​​QT初体验&#xff1a;手把手带你写一个自己的串口助手_qt设计串口助手的流程图-CSDN博客 Qt之串口编程&#xff08;添加QSerialPort模块&#xff09;_如何安装 qt串口模块教程-CSDN博客 串口调试助手&#xff1…

纯golang开发的mqtt server

Mochi-MQTT Server github地址&#xff1a;https://github.com/mochi-mqtt/server Mochi-MQTT 是一个完全兼容的、可嵌入的高性能 Go MQTT v5&#xff08;以及 v3.1.1&#xff09;中间件/服务器。 Mochi MQTT 是一个完全兼容 MQTT v5 的可嵌入的中间件/服务器&#xff0c;完…

【C语言】每日一题,快速提升(3)!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 题目&#xff1a;杨辉三角 在屏幕上打印杨辉三角。 1 1 1 1 2 1 1 3 3 1 ……......... 解答&#xff1a; 按照题设的场景&#xff0c;能发现数字规律为&#xff1…

Flink学习(六)-容错处理

前言 Flink 是通过状态快照实现容错处理 一、State Backends 由 Flink 管理的 keyed state 是一种分片的键/值存储&#xff0c;每个 keyed state 的工作副本都保存在负责该键的 taskmanager 本地中。 一种基于 RocksDB 内嵌 key/value 存储将其工作状态保存在磁盘上&#x…