基于FPGA的以太网设计(一)
以太网简介
以太网(Ethernet)是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以太网的技术标准,它规定了包括物理层的连线、电子信号和介质访问控制的内容。以太网是目前应用最普遍的局域网技术,取代了其他局域网标准如令牌环、FDDI和ARCNET。
以太网的标准拓扑结构为总线型拓扑,但目前的快速以太网(100BASE-T、1000BASE-T标准)为了减少冲突,将能提高的网络速度和使用效率最大化,使用交换机(Switch hub)来进行网络连接和组织。如此一来,以太网的拓扑结构就成了星型;但在逻辑上,以太网仍然使用总线型拓扑和CSMA/CD(Carrier Sense Multiple Access/Collision Detection,即载波多重访问/碰撞侦测)的总线技术。
以太网只是组成互联网的一个子集,以太网是现在主流的局域网标准,而互联网是指将大量的局域网连接起来,进行资源的分享。另外,互联网与以太网是两个不同的概念,前者是范围概念,后者是技术概念。互联网(Internet)、广域网(WAN)、局域网(LAN)可以算作一类,它们都是按照区域和范围来分类的。而以太网(Ethernet)、ATM网和FDDI网可以算作一类,它们是按照传输技术分类的。
下面是一个局域网的示意图:
-
OSI七层模型
为了实现网络通信的标准化,国际标准化组织(International Organization for Standardization,ISO)将整个以太网通信结构制定了 OSI (Open System Interconnection)模型,即开放式系统互联模型,也就是著名的7层网络模型。其示意图如下:
OSI7层模型只是个理想模型,相当于开发商提供的参考设计,它并不是强制规范,一般的网络系统只涉及其中几层就可以完成通信。以最常见的TCP/IP协议为例,它就只分为了4层或者5层。4层和5层的差异在于,是否将最底层的两层合并了。
-
第一层与第二层
以太网在第 1 层上涉及信号、在介质中传输的比特流、将信号放到介质上的物理组件以及各种拓扑,它在设备之间的通信中扮演主要角色。
数据链路子层极大地促进了技术兼容性和计算机通信。
(1)MAC 子层负责将要用于传送信息的物理组件,并且准备通过介质传输的数据。
(2)逻辑链路控制 (LLC) 子层保持通信过程所用物理设备的相对独立性。
LLC 子层获取网络协议数据(通常是IPv4 数据包)并加入控制信息,帮助将数据包传送到目的节点。第 2 层通过 LLC 与上层通信。
逻辑链路控制(LLC)
1.建立与上层的连接
2.将网络层数据包封装成帧
3.标识网络层协议
4.保持物理设备的相对独立性
MAC——获取到介质的数据
介质访问控制 (MAC) 是数据链路层以太网子层的下半层,由硬件(NIC)实现
以太网 MAC 子层主要有两项职责
(1)数据封装
(2)介质访问控制
数据封装:帧定界、编址、错误检测
介质访问控制:对于将帧放入介质中和从介质中取下帧实施控制、介质恢复
-
其它层
网络层:网络层通过 IP 寻址来建立两个节点之间的连接,为源端的运输层送来的组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的传输层,就是我们常说的 IP 层。
传输层:传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。主要协议 TCP、UDP。
应用层:OSI 参考模型中最靠近用户的一层,为计算机用户提供应用接口和各种网络服务。主要协议:HTTP,HTTPS,FTP,POP3、SMTP、SNMP、DHCP、 DNS。
传输层用得最多的两个协议:TCP和UDP。它们俩最大的区别就是TCP是通信双方是有链接的,可靠的通信;而UDP则是无连接的,不可靠的通信。
TCP通信需要通过“3次握手,4次挥手”来建立连接,所以通信比较可靠,但是因为多出来了这些多余的动作,所以传输速度通常比UDP慢,适合可靠性要求高的场合。UDP通信则不需要建立连接,直接往对面发就完事了,管你收到没收到,收到你命好,收不到也不关我的事,反正就是一句话:听天由命。因为这个特性UDP传输不可靠,容易丢包,误码率高,但是对应的,传输速度就比较快一点,比较适合语音通话、视频通话这种应用场合,偶尔丢几帧没关系,只要别一直卡着就行。
网络层用得最多的是IP协议,它解决的是如何从一个局域网传输到另一个局域网的问题,实现这一功能主要依靠IP地址和路由交换机制。
-
MAC地址
MAC地址,全称为 Media Access Control address,即媒体访问控制地址,由6个字节共48 位组成,理论上,每台主机(网卡)的MAC地址都是唯一的。
MAC 地址是由 IEEE(电气和电子工程师协会)的注册管理机构分配的。地址的前半部分(前三组十六进制数字,称为 OUI,组织唯一标识符)用于标识设备制造商。每个制造商都有一个或多个唯一的 OUI 代码。后半部分(后三组十六进制数字)则由制造商自行分配给其生产的每个设备,确保每个设备的 MAC 地址在其生产的所有设备中是唯一的。
为了处理好MAC地址和交换机端口的对应关系,在交换机内部还维护着一张MAC地址表,它记录着每一个 MAC 地址的设备,连接在其交换机的哪一个端口上。
在一个局域网中,不同的设备通过交换机来进行信息的传递,假设一个局域网网中有三台设备,主机0想要与主机1进行通信,那么就需要向交换机发送信息+主机1的MAC地址,交换机再向所有设备都发送信息+MAC地址,主机接收到之后与自己的MAC地址进行比较,如果不相同则说明信息不是发送给自己的,将信息丢弃;如果相同则说明信息是发送给自己的,接收信息。同时给交换机发送一个信号,说明自己收到了信息,那么交换机就知道了本次接收信息主机的MAC地址,并将该地址记录到MAC地址表中。
-
IP地址
尽管MAC地址是唯一的,但是它有个致命的问题就是:一个局域网内的MAC地址很可能没规则。MAC地址就像人的姓名,因为不同的网卡可能来自不同的设备商,所以编码很难有什么相同的地方,但是学号就是IP地址,它是有地域性的,一个局域网内不同主机分配的IP都有相同的前缀。
IP地址有两个版本,IPv4和IPv6,因为目前IPv4仍是主流,所以本文就只讲IPv4了。IPv4一共有4个字节32位,一共可以表示的地址数是2^32 = 4,294,967,296,约43亿个。IP 地址(IPv4 地址)由32位正整数来表示,IP 地址在计算机是以二进制的方式处理的。人类为了方便记忆采用了点分十进制的标记方式,也就是将 32 位 IP 地址以每 8 位为组,共分为4组,每组以 . 隔开,再将每组转换成十进制。
IP 地址分类成了 5 种类型,分别是 A 类、B 类、C 类、D 类、E 类。
最大主机个数,就是要看主机号的位数,如 C 类地址的主机号占 8 位,那么 C 类地址的最大主机个数:2^8 - 2 = 254。
为什么要减 2 呢?因为在 IP 地址中,有两个 IP 是特殊的,分别是主机号全为 1 和 全为 0 地址。主机号全为 1 指定某个网络下的所有主机,用于广播;主机号全为0指定某个网络。
这种IP 分类方式有两个大的缺点:
- 同一网络下没有地址层次,比如一个公司里用了 B 类地址,但是可能需要根据生产环境、测试环境、开发环境来划分地址层次,而这种 IP 分类是没有地址层次划分的功能,所以这就缺少地址的灵活性。
- A、B、C类有个尴尬处境,就是不能很好的与现实网络匹配。
- C 类地址能包含的最大主机数量实在太少了,只有 254 个,一个大点儿的网吧都不够用。
- 而 B 类地址能包含的最大主机数量又太多了,6 万多台机器放在一个网络下面,一般的企业基本达不到这个规模,闲着的地址就是浪费。
这两个缺点,都可以在CIDR无分类地址解决。CIDR无分类地址这种方式不再有分类地址的概念,32 比特的 IP 地址被划分为两部分,前面是网络号,后面是主机号。表示形式 a.b.c.d/x
,其中 /x
表示前 x 位属于网络号, x 的范围是0~32,这就使得 IP 地址更加具有灵活性。
比如 192.168.1.2/24,这种地址表示形式就是 CIDR,/24 表示前 24 位是网络号,剩余的 8 位是主机号。
还有另一种划分网络号与主机号形式,那就是子网掩码,掩码的意思就是掩盖掉主机号,剩余的就是网络号。将子网掩码和 IP 地址按位计算 AND,就可得到网络号。子网掩码实际上就是前面一串1加后面1串0,因为任何数和1相与都是其自身,而任何数和0相与都是0,所以子网掩码实际上就是那串1规定了IP地址的网络号长度,比如子网掩码为255.255.255.0,就是前面24个1加后面8个0,这样和IP地址相与,得到的实际就是前面24位的值+后面8个0。
子网掩码最大的作用就是判断两个IP是否在同一个子网,比如192.168.1.1/24和192.168.1.2/24,它们的子网掩码都是255.255.255.0,进行相与运算后,值都是192.168.1.0,所以这两个IP都是处于同一个子网(即同一个局域网内)。
回到上面的多台主机通信的案例,不同的局域网的主机之间通信,如果只靠MAC地址,那么寻址是非常不方便的。
如何连接多个局域网呢?此时每台主机除了MAC地址外,还有一个IP地址:
因为同一局域网的主机的MAC地址没有规律,所以路由器不得不为所有的主机都建立一个MAC地址的对应关系,随着主机的增多,这个表将会变得巨大,所需要的存储空间也非常大,这无疑显得性价比和效率都极低。而使用了IP地址,则同一局域网内的主机都有相同的网络号,为此,一个网络号可以对应多台主机,那么路由器所需要的存储空间就小了很多。2个子网连接的示意图如下:
当子网比较多的时候一个路由器明显是不够的,因此不同的路由器之间也可以互相连接,所以每个路由器的每个端口也应该有一个ip地址。
同样的,因为不同的子网间主机无法直接通信(不是同一个局域网的设备),它们如果要通信只能通过各自对应的路由器端口来通信,所以路由器的每个端口也需要一个MAC地址,这样才能完成局域网的通信。
现在有个新问题,就是主机怎么知道谁是路由器?或者说路由器的IP是多少呢?
其实说发给路由器不准确,应该说 A 会把包发给默认网关。对 A 来说,A 只能直接把包发给同处于一个子网下的某个 IP 上,所以发给路由器还是发给某个电脑,对 A 来说也不关心,只要这个设备有个 IP 地址就行。所以默认网关,就是 A 在自己电脑里配置的一个 IP 地址,以便在发给不同子网的机器时,发给这个 IP 地址。
不同子网主机的通信,比如A发数据给C,A发现和C不在一个子网后,就会把数据发给路由器即默认网关,那么路由器是怎么知道C在哪里的呢?
前面说过交换机里边有个对应MAC地址和端口映射关系的表,同样的道理,也可以在路由器里边搞个路由表来存储不同的IP地址和端口之间的映射关系。但是要注意的是,因为端口是有限的,而连接的子网却可以有很多个,所以有时候两个子网之间并不会有直接映射关系,而是要通过多个路由表才能到达最后的子网。这就好比,你要从县城去纽约,可能首先需要去省城,然后从省城去北京,最后才从北京飞到纽约。
从一个路由器跳到下一个路由器称之为下一跳(Hop),只要路由算法算好了,那就一定可以通过有限个路由器把数据传递出去,那么每一个路由器只要记录下一跳地址就行了。就像你想从县城去纽约,跑到火车站买票,工作人员说不行,你只能先去省城(对县城的工作人员来说,下一跳地址就是省城)。去了省城的飞机场买票,工作人员又说去不了,只能去北京做飞机(对省城的工作人员来说,下一跳地址就是北京),到了北京就终于能去纽约了,这几段路程就是在不同路由器之间的下一跳。
-
以太网帧格式
在以太网链路上的数据包称作以太网帧。以太网帧起始部分由前导码和帧开始符组成。后面紧跟着一个以太网报头,以MAC地址说明目的地址和源地址。帧的中部是该帧负载的包含其他协议报头的数据包(例如IP协议、ARP协议)。以太帧由一个32位冗余校验码结尾。它用于检验数据传输是否出现损坏。以太网帧格式如下图所示。
1.前导码和帧开始符是固定的,为7个0x55紧跟着1个0xd5
2.目的MAC地址指明帧的接受者
3.源MAC地址指明帧的发送者
4.以太网类型,指示帧的类型,比如0x0800表示该帧是IP数据包,0x0806表示该帧是ARP协议数据包
5.数据和填充就是所承载的数据包,跟前面以太网类型对应。
6.帧校验序列是一个32位的循环校验码(FCS)。
ARP协议,全称为Address Resolution Protocol,即地址解析协议,ARP协议属于以太网帧的一种,前面以太网帧介绍中有说到,我们如果从设备A发送以太网帧到设备B,我们不可能每次都进行广播,那么设备A如何知道设备B的物理地址呢?ARP协议就是为了解决这个问题。
首先设备A广播,发送ARP请求,等收到设备B的ARP应答以后就能知道设备B的MAC地址。ARP帧格式如下图所示
ARP字段就是前面以太网帧待填充的数据。硬件类型、上层协议类型、MAC地址长度、IP地址长度均固定不变。
假设设备A的IP地址为192.168.0.2,MAC地址为0x00_0a_35_01_fe_c0,我们知道目的IP地址为192.168.0.3,不知道该IP地址对应的MAC地址,如果设备A想要和IP地址为192.168.0.3的设备B进行通信(如UDP或者IP通信),就必须知道它的MAC地址。此时设备A就需要广播发送ARP请求,接收方MAC地址填0xff_ff_ff_ff_ff_ff。这样IP地址为192.168.0.3的设备就会解析出这是一个ARP请求,它询问自身的MAC地址,此时它就会做出ARP应答,将自身的MAC地址发送给对应IP地址的设备A。
注意发送ARP请求时,操作码为0x0001,应答时操作码为0x0002。
基于FPGA的以太网设计(1)----大白话解释什么是以太网_zynq 以太网描述符-CSDN博客
基础知识——以太网(Ethernet )-CSDN博客
FPGA学习之路:深入剖析以太网原理_以太网数据帧格式fpga-CSDN博客
相关文章:

基于FPGA的以太网设计(一)
以太网简介 以太网(Ethernet)是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以太网的技术标准,它规定了包括物理层的连线、电子信号和介质访问控制的内容。以太网是目前应用最普遍的局域网技术,取代了其他局域网标准如…...

Insert into on duplicate key update 死锁问题解析
Insert into on duplicate key update 死锁问题解析 背景 前段时间的需求中有这个么一个场景,每天早上需要通过定时任务到不同的平台拉取一些广告投放的相关数据,涉及的表比较多,数据量也比较大,有的需要全量同步,有…...

Apache Lucene 10 已发布!Lucene 硬件效率改进及其他改进
作者:来自 Elastic Adrien Grand Apache Lucene 10 刚刚发布,重点关注硬件效率!查看主要版本亮点。 Apache Lucene 10 终于发布了!自 Lucene 9.0(于 2021 年 12 月发布,距今已有近 3 年)以来&a…...

【SQL】SQL查询语句
目录 🎄 基本查询语法 ⭐查询多个字段 ⭐设置别名 ⭐去除重复记录 ⭐ 数据准备 ⭐ 案例 🎄 条件查询 ⭐ 语法 ⭐ 案例 🎄 聚合函数 ⭐ 介绍 ⭐ 常见的聚合函数 ⭐ 语法 ⭐ 案例 🎄 分组查询 ⭐ 语法 ⭐ where与having的区…...

AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型(LLM)应用开发平台
AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型(LLM)应用开发平台 目录 AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型(LLM)应用开发平台 一、简单介绍 二、Docker 下载安…...
机器学习摘下诺奖桂冠
前言 近日,2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者,这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家,如今却将全球范围内对机器学习和神经网络的研究和开发作为了一…...

营销邮件软件:提升邮件营销效率必备工具!
营销邮件软件选择技巧?免费高效的邮件营销软件推荐? 如何高效地管理和优化邮件营销活动成为了企业面临的一大挑战。营销邮件软件成为提升邮件营销效率的必备工具。MailBing将深入探讨营销邮件软件的功能、优势以及如何选择合适的工具。 营销邮件软件&a…...

鸿蒙开发 四十五 鸿蒙状态管理(嵌套对象界面更新)
当运行时的状态变量变化,UI重新渲染,在ArkUI中称为状态管理机制,前提是变量必须被装饰器修饰。不是状态变量的所有更改都会引起刷新,只有可以被框架观测到的更改才会引起UI刷新。其中boolen、string、number类型,可观察…...

第 6 章:vue-router
1. router 相关理解 1.1 vue-router 的理解 vue 的一个插件库,专门用来实现 SPA 应用 1.2 对 SPA 应用的理解 单页 Web 应用(single page web application,SPA)。整个应用只有一个完整的页面。点击页面中的导航链接不会刷新页…...
PaddleOCR模型转换、部署全流程(Ubuntu系统)_随记2
本篇衔接文章1、环境流程需要看随记1就可以 PaddleOCR环境搭建、模型训练、推理、部署全流程(Ubuntu系统)_随记1 一、ONNX导出 1、环境准备 主要参考官方技术文档:官方技术文档 未完做完更新... 参考:PaddleOCR-PP-OCRv4推理详解…...

Tableau 2024.3 发布!表格可视化项扩展、空间参数和 Cloud 管理器等,助力企业大规模分析
在升级至最新版前,先来详细一览 Tableau 2024.2 的最新特性吧~ Tableau 发布新版本啦!作为今年的收官之作,Tableau 2024.3 在延续经典之余,也为用户带来了不少惊喜,让企业数据分析之旅更加丰富多彩。 使用 Tableau Cl…...

即时通讯增加kafka渠道
此次给im服务增加kafka渠道,刚好最近有对SpringCloudStream进行了解,刚好用来练练手 增加kafka渠道 pom.xml 引入stream相关依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-strea…...
建造者模式和工厂模式的区别
工厂模式和建造者模式都是创建型设计模式,它们的主要作用都是为了简化对象的创建过程,但是它们在设计意图和实现细节上有着显著的区别。 总结区别: 关注点不同: 工厂模式关注的是对象的创建。建造者模式关注的是对象的构造过程…...

GEE数据集——ERA5-陆地每日汇总--ECMWF气候再分析数据集
目录 简介 数据集说明 Dataset Availability Dataset Provider Collection Snippet 空间信息 Resolution Bands Table 变量 代码 代码链接 结果 引用 许可 网址推荐 0代码在线构建地图应用 机器学习 简介 注(2024-04-19): …...
Spring Boot 中的 @RequestMapping 和 Spring 中的 @RequestMapping 有什么区别?
在Spring框架中,RequestMapping注解用于映射Web请求到处理器(Controller)的方法上。在Spring Boot中,这个注解的使用方式和目的与Spring框架中是完全相同的。RequestMapping注解可以用于类或方法上,以声明请求的映射。…...

PROFINET开发或EtherNet/IP开发嵌入式归一板有用于工业称重秤
这是真实案例。然而,客户选择不展示其品牌名称。 Anybus嵌入式解决方案帮助工业称重设备制造商连接到任何工业网络。多网络连接使称重设备能够轻松访问不同的控制系统,从而加快上市时间。 我们最终找到了HMSNetworks的Anybus解决方案。他们的成熟技术和专…...

【Kafka】Kafka源码解析之producer过程解读
从本篇开始 打算用三篇文章 分别介绍下Producer生产消费,Consumer消费消息 以及Spring是如何集成Kafka 三部分,致于对于Broker的源码解析,因为是scala语言写的,暂时不打算进行学习分享。 总体介绍 clients : 保存的是Kafka客户端…...

深度学习笔记20_数据增强
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 一、我的环境 1.语言环境:Python 3.9 2.编译器:Pycharm 3.深度学习环境:TensorFlow 2.10.0 二、GPU设置…...
模板变量与php变量对比做判断
${item.create_name}如何与php变量对比 在PHP中,您可以通过将字符串内嵌到双引号中来将模板变量 ${item.create_name} 与PHP变量进行对比。如果您有一个PHP变量 $phpVariable 并且想要检查它是否与 ${item.create_name} 相同,您可以使用 str_replace 函…...

C语言 | Leetcode C语言题解之第485题最大连续1的个数
题目: 题解: int findMaxConsecutiveOnes(int* nums, int numsSize) {int maxCount 0, count 0;for (int i 0; i < numsSize; i) {if (nums[i] 1) {count;} else {maxCount fmax(maxCount, count);count 0;}}maxCount fmax(maxCount, count);…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...

C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...