OSPF协议介绍

OSPF协议介绍概述路由协议 OSPF 全称为 OpenShortest 也就开放的最短路径优先协议 因为 OSPF 是由 IETF 开发的 它的使用不受任何厂商限制 所有人都可以使用 所以称为开放的 而最短路径优先 SPF 只是 OSPF 的核心思想 其使用的算法是 Dijkstra 算法 最短路径优先并没有太多特殊的含义 并没有任何一个路由协议是最长路径优先的 所有协议 都会选最短的 OSPF 的流量使

概述

路由协议OSPF全称为Open Shortest Path First,也就开放的最短路径优先协议,因为OSPF是由IETF开发的,它的使用不受任何厂商限制,所有人都可以使用,所以称为开放的,而最短路径优先(SPF)只是OSPF的核心思想,其使用的算法是Dijkstra算法,最短路径优先并没有太多特殊的含义,并没有任何一个路由协议是最长路径优先的,所有协议,都会选最短的。

  • OSPF的流量使用IP协议号89。
  • OSPF工作在单个AS,是个绝对的内部网关路由协议(Interior Gateway Protocol,即IGP)。
  • OSPF对网络没有跳数限制,支持 Classless Interdomain Routing (CIDR)和Variable-Length Subnet Masks (VLSMs),没有自动汇总功能,但可以手工在任意比特位汇总,并且手工汇总没有任何条件限制,可以汇总到任意掩码长度。
  • OSPF支持认证,并且支持明文和MD5认证;OSPF不可以通过Offset list来改变路由的metric。
  • OSPF并不会周期性更新路由表,而采用增量更新,即只在路由有变化时,才会发送更新,并且只发送有变化的路由信息;事实上,OSPF是间接设置了周期性更新路由的规则,因为所有路由都是有刷新时间的,当达到刷新时间阀值时,该路由就会产生一次更新,默认时间为1800秒,即30分钟,所以OSPF路由的定期更新周期默认为30分钟。
  • OSPF所有路由的管理距离(Ddministrative Distance)为110,OSPF只支持等价负载均衡。
  • 距离矢量路由协议的根本特征就是自己的 路由表是完全从其它路由器学来的,并且将收到的路由条目一丝不变地放进自己的路由表,运行距离矢量路由协议的路由器之间交换的是路由表,距离矢量路由协议 是没有大脑的,路由表从来不会自己计算,总是把别人的路由表拿来就用;而OSPF完全抛弃了这种不可靠的算法,OSPF是典型的链路状态路由协议,路由器之间交换的并不是路由表,而是链路状态,OSPF通过获得网络中所有的链路状态信息,从而计算出到达每个目标精确的网络路径。

术语

Router-id

Cost

  • OSPF会自动计算接口上的Cost值,但也可以通过手工指定该接口的Cost值,手工指定的优先于自动计算的值。
  • OSPF计算的Cost,同样是和接口带宽成反比,带宽越高,Cost值越小。到达目标相同Cost值的路径,可以执行负载均衡,最多6条链路同时执行负载均衡。

链路(Link)

就是路由器上的接口,在这里,应该指运行在OSPF进程下的接口。

链路状态(Link-State)

链路状态(LSA)就是OSPF接口上的描述信息,例如接口上的IP地址,子网掩码,网络类型,Cost值等等,OSPF路由器之间交换的并不是路由表,而是链路状态(LSA),OSPF通过获得网络中所有的链路状态信息,从而计算出到达每个目标精确的网络路径。OSPF路由器会将自己所有的链路状态毫不保留地全部发给邻居,邻居将收到的链路状态全部放入链路状态数据库(Link-State Database),邻居再发给自己的所有邻居,并且在传递过程种,绝对不会有任何更改。通过这样的过程,最终,网络中所有的OSPF路 由器都拥有网络中所有的链路状态,并且所有路由器的链路状态应该能描绘出相同的网络拓朴。

OSPF区域

可以配置任何OSPF路由器成为ABR或ASBR。

由于OSPF有着多种区域,所以OSPF的路由在路由表中也以多种形式存在,共分以下几种:

  • 如果是同区域的路由,叫做Intra-Area Route,在路由表中使用O来表示;
  • 如果是不同区域的路由,叫做Inter-Area Route或Summary Route,在路由表中使用O IA来表示;
  • 如果并非OSPF的路由,或者是不同OSPF进程的路由,只是被重分布到OSPF的,叫做External Route,在路由表中使用O E2或OE 1来表示。

邻居(Neighbor)

邻接(Adjacency)

两台OSPF路由器能够形成邻居,但并不一定能相互交换LSA,只要能交换LSA,关系则称为邻接(Adjacency)。邻居之间只交换Hello包,而邻接(Adjacency)之间不仅交换Hello包,还要交换LSA。

DR/BDR

因为所有路由器都能与DR和BDR互换LSA,所以所有路由器都与DR和BDR是邻接(Adjacency)关系,而Drother与Drother之间无法互换LSA,所以Drother与Drother之间只是邻居关系。

OSPF数据包交换过程

Hello

Hello包是用来建立和维护OSPF邻居的,要交换LSA,必须先通过Hello包建立OSPF邻居。

Database Description Packets (DBD)

邻居建立之后,并不会立刻就将自己链路状态数据库中所有的LSA全部发给邻居,而是将LSA的基本描述信息发给邻居,这就是Database Description Packets (DBD),是LSA的目录信息,相当于书的目录,邻居在看完DBD之后,就能知道哪些LSA是需要邻居发送给自己的。

Link-state Request (LSR)

邻居在看完发来的LSA描述信息(DBD)之后,就知道哪些LSA是需要邻居发送给自己的,自己就会向邻居发送LSA请求(LSR),告诉邻居自己需要哪些LSA。

Link-state update(LSU)

当邻居收到其它路由器发来的LSA请求(LSR)之后,就知道对方需要哪些LSA,然后根据LSR,将完整的LSA内容全部发给邻居,以供计算路由表。

LSDB

就是已经收到了所有需要邻居发给自己的LSA,这时的链路状态数据库已经达到收敛状态。

OSPF启动过程

每个过程详细情况如下:

Down

路由器刚刚启动OSPF进程,还没有从任何路由器收到任何数据包,Hello包也没有收到,在此进程,可以向外发送Hello包,以试图发现邻居。

Attempt

因为OSPF使用组播发送数据包,如使用组播发送Hello包,如果Hello包不能发出去被其它路由器收到,就不能和其它路由器建立OSPF邻居;在一些组播不能发送的网络中,例如帧中继这样的非广播网络环境,组播不能够传递,在这种情况下,就需要指定OSPF使用单播向邻居发送Hello包,以此试图和指定的邻居建立OSPF邻居关系,在此状态下,OSPF称为Attempt状态。

Init

只是OSPF路由器一方收到了另一方的Hello,但并没有双方都交换Hello,也就是对方的Hello中还没有将自己列为邻居。

Two-way

双方都已经交换了Hello信息,并且从Hello中看到对方已经将自己列为邻居,此状态,就表示OSPF邻居关系已经建立,并且如果是需要选举DR和BDR的话,也已经选举出来,但OSPF邻居之间并不一定就会交换LSA,如果不需要交换LSA,则永远停留在此状态,如果需要形成邻接并互相交换LSA,则状态继续往下进行。(比如Drother与Drother之间将永远停留在Two-way状态,因为Drother与Drother之间不需要交换LSA。)

Exstart

因为在OSPF邻居之间交换完整的LSA之前,会先发送Database Description Packets (DBD),Link-state Request (LSR)等数据包,邻居之间是谁先发,谁后发,需要确定顺序,在Exstart状态,就是确定邻居之间的主从关系(Master—Slave关系),Router-ID数字大的为主路由器,另一端为从路由器,由主路由器先向从路由器发送信息。在选举DR与BDR的网络环境中,并不一定DR就是主路由器,BDR就是从路由器,因为DR和BDR可以通过调整接口优先级来控制,所以DR也许是因为优先级比BDR高,而Router-ID并不比BDR高。

在任何网络环境下,OSPF在交换LSA之前,都需要确定主从关系。

Exchange

就是交换Database Description Packets (DBD)的过程,DBD只是LSA的简单描述,只包含LSA的一些头部信息,收到DBD的路由器会和自己的链路状态数据库作对比,确定需要哪些LSA的完整信息,就会发送LSR请求给邻居。

Loading

邻居根据收到的LSR(Link-State Request),向对方回复Link-state update(LSU)。

Full

等到OSPF都收到了邻居回复的所有Link-state update(LSU),那么此时的数据库状态就变成了收敛状态,此状态就是Full状态,但此时只是数据库已经同步,但路由表却还在计算当中。

除了Two-way和Full这两个状态,邻居停留在任何状态,都是不正常。

OSPF网络类型(Network Type)

OSPF是一个在各方面都考虑比较周全的路由协议,也会因此将该协议变得更为复杂化,OSPF并不像RIP与EIGRP那样,RIP与EIGRP在运行时,并不考虑OSI模型在二层所定义的内容,即并不关心二层的链路介质类型,而OSPF在运行时,必须考虑链路层的类型,称为OSPF网络类型(Network Type),对于不同二层介质类型,OSPF将有不同的操作和运行过程,网络类型,可分为如下几种:

  • 点到点(Point-To-Point)
  • 点到多点(Point-To-Multipoint )
  • 广播(Broadcast )
  • 非广播(Non-Broadcast )
  • 点到多点非广播(Point-To-Multipoint Non-Broadcast)

对于不同的网络类型,将会影响到OSPF的Hello时间与Dead时间,关系到DR与BDR的选举与否,影响到OSPF邻居是自动建立还是手工建立,总结如下:

网络类型 Hello时间 选举DR/BDR 邻居建立方式
点到点(p2p) 10s 自动
点到多点(p2mp) 30s 自动
广播(Boradcast) 10s 自动
非广播(Non-B) 30s 手工
点到多点非广播(p2mp-Non-B) 30s 手工

OSPF链路类型(Link Type)

OSPF确实因为考虑问题的全面,而导致路由协议的复杂,OSPF不仅因为不同的二层链路层介质定义了不同的OSPF网络类型(Network Type),还因为链路上的邻居,而定义了OSPF链路类型(Link Type) 。

OSPF网络类型(Network Type)是完全根据二层链路层的介质决定的,而OSPF链路类型(Link Type)不仅受二层链路层介质的影响,还受到链路中OSPF邻居的影响,同时还影响到LSA,因此变得复杂。

OSPF链路类型(Link Type)分为以下几种:

Stub Network Link

在一个网段中只有一台OSPF路由器的情况下,该网段被OSPF链路类型定义为Stub Network Link;因为一个网段中只有一台OSPF路由器,所以在这个网段就不可能有OSPF邻居,一个接口被通告进OSPF,无论其二层链路是什么介质,只要在该接口上没有OSPF邻居,那么就是Stub Network Link;Loopback接口永远被定义为Stub Network Link,默认使用32位掩码表示,无论将Loopback接口改为哪种OSPF网络类型(Network Type),始终改变不了它的OSPF链路类型(Link Type)属性,但可以改变它在LSA中的掩码长度。

Point-To-Point Link

OSPF网络类型(Network Type)为Point-To-Point的接口,OSPF链路类型(Link Type)为Point-To-Point Link,但Loopback接口除外;而网络类型为点到多点(Point-To-Multipoint)的接口,同样链路类型也为Point-To-Point Link。

Point-To-Point Link可以是手工配置的地址(Numbered),也可以是借用的地址(Unnumbered),也可以是物理接口或逻辑子接口。

Transit Link

拥有两台或两台以上OSPF路由器的链路,简单理解为有邻居的OSPF接口就是Transit Link,但网络类型为Point-To-Point和点到多点(Point-To-Multipoint)的接口除外,因为它们被定义为Point-To-Point Link。

Virtual link

就是OSPF虚链路(Virtual Link),但希奇的是,虚链路(Virtual Link)被定义为手工配置的地址(Numbered)的Point-To-Point Link。

OSPF外部路由

OSPF同其它路由协议一样,可以将其它外部协议的路由信息或其它OSPF进程的路由信息重分布进自己的域内,这样的路由在OSPF域内就是OSPF外部路由(External Route),在路由表中的表示方法和OSPF自己的路由会有所不同,因为OSPF外部路由可以分为两类,分为Type 2和Type 1,所以在路由表中分别表示为OE2和OE1。

所以必须给每一个OSPF路由器定义一个身份,就相当于人的名字,这就是Router-ID,并且Router-ID在网络中绝对不可以有重名,否则路由器收到的链路状态,就无法确定发起者的身份,也就无法通过链路状态信息确定网络位置,OSPF路由器发出的链路状态都会写上自己的Router-ID,可以理解为该链路状态的签名,不同路由器产生的链路状态,签名绝不会相同。

重分布外部路由时,默认类型为O E2,如果通过两个ASBR能到达相同的外部路由,选择O E1的优先,其次是O E2,但如果都为O E1或O E2,则选择到达Forward Address最小Metric的路径优先,如果Forward Address都为0.0.0.0,最后选择到达ASBR最小Metric的路径优先,但如果Forward Address地址一个为0.0.0.0,一个为真实地址,统一比较到ASBR的Metric。

OSPF末节区域

如果路由增加,就意味着LSA的增加,有时,在一个末梢网络中,许多路由信息是多余的,并不需要通告进来,因为一个OSPF区域内的所有路由器都能够通过该区域的ABR去往其它OSPF区域或者OSPF以外的外部网络,既然一个区域的路由器只要知道去往ABR,就能去往区域外的网络,所以可以过滤掉区域外的路由进入某个区域,这样的区域称为OSPF末节区域(Stub Area);一个末节区域的所有路由器虽然可以从ABR去往区域外的网络,但路由器上还是得有指向ABR的路由,所以末节区域的路由器只需要有默认路由,而不需要明细路由,即可与区域外的网络通信,根据末节区域过滤掉区域外的不同路由,可将末节区域分为如下四类:

  • Stub Area(末节区域)
  • Totally Stub Area(完全末节区域)
  • Not-so-Stubby Area(NSSA)
  • Totally Not-so-Stubby Area(Totally NSSA)

各类型的特征如下:

Stub Area(末节区域)

Totally Stub Area(完全末节区域)

可以发现,末节区域与完全末节区域的不同之处在于,末节区域可以允许其它OSPF区域的路由(Inter-Area Route)进入,而完全末节区域却不可以。

Not-so-Stubby Area(NSSA)

NSSA与末节区域的最大区别在于,NSSA区域可以允许自身将外部路由重分布进OSPF,而末节区域则不可以。

Totally Not-so-Stubby Area(Totally NSSA)

Totally NSSA与NSSA的区别在于,NSSA区域可以允许其它OSPF区域的路由(Inter-Area Route)进入,而Totally NSSA区域却不可以,但Totally NSSA区域的ABR会自动向Totally NSSA区域内发送一条指向自己的默认路由。

总结各区域的特征如下:

区域类型 接收区域间路由 ABR是否发送默认路由 是否可以重分布外部路由
Stub Area
Totally Stub Area
NSSA
Totally NSSA
  • 在末节区域下,ABR自动发出的默认路由,Metric值默认为1,可通过命令area area-id default-cost cost修改,默认路由除了默认的Cost值以外,还会累加真实接口的Cost值。
  • 骨干区域不能配置为任何末节区域。
  • 当将某个区域配置为末节区域后,则区域中所有路由器都必须配置为末节区域,因为配置为末节区域的路由器上所有接口发出的Hello包中都会有末节标签,所有如果对方没有末节标签,则不能成为邻居。

OSPF LSA类型

OSPF中共有11类LSA,而在CCIE的要求中,只需要理解1、2、3、4、5、7共6类即可,这些LSA会因为区域类型,网络类型,链路类型,路由器身份的不同而不同,以下是详细介绍:

类型 1 (Router Link)

类型 2 (Network Link)

类型2的LSA只有在需要选举DR/BDR的网络类型中才会产生,并且只是DR产生,BDR没有权利产生,LSA 2与LSA 1没有任何关联,没有任何依存关系,是相互独立的。

类型 3 (Summary Link)

类型3的LSA就是将一个区域的LSA发向另一个区域时的汇总和简化,ABR其实就是将LSA 1汇总和简化,变成LSA 3后再发到另一个区域的,如果是详细完整的LSA 1,是绝不允许的,LSA 3是LSA 1的缩略版。

类型 4 (ASBR Summary Link)

对于外部路由,执行重分布的路由器ASBR在LSA中写上自己的Router-ID,然后传递到多个OSPF区域,所以会被多个ABR转发,而ABR在转发外部路由的LSA时,是没有权限修改LSA的Router-ID,这样一来,外部路由的Router-ID在所有OSPF路由器上都不会改变,永远是ASBR的Router-ID,最终造成的结果是只有与ASBR同在一个区域的路由器才能到达外部路由,因为只有与ASBR同在一个区域的路由器才知道如何到达ASBR的Router-ID,而其它区域的路由器对此却无能为力;为了能够让OSPF所有区域都能与外部路由连通,在ABR将外部路由从ASBR所在的区域转发至其它区域时,需要发送单独的LSA来告知如何到达ASBR的Router-ID,因为ABR将外部路由的LSA告诉了其它区域,是有义务让它们与外部路由可达的,所以额外发送了单独的LSA来告知如何到达ASBR的Router-ID;这个单独的LSA就是类型4的LSA,LSA 4是包含的ASBR 的Router-ID,只要不是ASBR所在的区域,都需要ABR发送LSA 4来告知如何去往ASBR。

类型 5 (External Link)

类型5的LSA就是外部路由重分布进OSPF时产生的,并且是由ASBR产生的,LSA中包含ASBR的Router-ID,任何路由器都不允许更改该Router-ID,LSA 5中还包含Forward Address,对于LSA 5 的Metric值计算与选路规则也有所不同,详细信息请见OSPF外部路由部分。

类型 7 (NSSA Link)

因为NSSA区域可以将外部路由重分布进OSPF进程,而NSSA不是一般的常规区域,所以在NSSA将外部路由重分布进OSPF时,路由信息使用类型7来表示,LSA 7由NSSA区域的ASBR产生,LSA 7也只能在NSSA区域内传递,如果要传递到NSSA之外的其它区域,需要同时连接NSSA与其它区域的ABR将LSA 7 转变成LSA 5后再转发。

LSA各参数

在LSA的内容中,将有多个参数来表示,这些参数会因为LSA类型,区域类型,网络类型,链路类型,路由器身份的不同而不同,是真正的变化多端,非常的复杂,这些参数在我们操作OSPF时,可以帮助我们更好的分析LSA,但并不会起决定性的作用,所以对LSA参数的理解与否,不会影响到OSPF的配置与排错,若无特殊要求,LSA参数需要大家了解即可,不需要掌握,不需要牢记。

LSA中包含的参数有LS Type,Link State ID,Link ID,Link Data,具体如下:

LS Type

LS Type就是前面讲到的LSA类型,如LSA 1,LSA 2,LSA 3,LSA 4,LSA 5,LSA 7。

Link State ID

因为OSPF接口的链路状态,是使用LSA发送的,接口的相关信息,如网络号,掩码等等,它们算是LSA真正的内容,而LSA也是有简明信息的,或者说是LSA的标题,或者说是LSA的名称,这就是Link State ID,如果将LSA比作一个包裹,那么Link State ID就是包裹外面写的信息,比如包裹里是一件衣服,那么Link State ID可能就是写的衣服是什么牌子,什么尺寸,什么颜色,等等;但不同类型的LSA,其Link State ID的表示也会不同,如下表:

LSA类型 Link State ID内容
LSA 1 是产生LSA 1的路由器的Router-ID
LSA 2 因为LSA 2是由DR产生的,所以LSA 2的Link State ID是DR的接口地址
LSA 3 是目标网络的网络地址,其实这个等同于路由条目
LSA 4 是ASBR的Router-ID
LSA 5 是目标网络的网络地址,其实这个等同于路由条目

Link ID

Link ID的具体内容如下表:

链路类型(Link Type) Link ID内容
Stub Network Link 使用接口的网络号和子网掩码来表示
Point-To-Point Link 邻居的Router-ID
Transit Link 是DR的接口地址
Virtual link 同Point-To-Point Link,是邻居的Router-ID

Link Data

是接口上的IP地址,如果链路类型(Link Type)为Stub Network Link,则Link Data是子网掩码。

OSPF虚链路(Virtual Link)

OSPF认证

同RIP和EIGRP一样,出于安全考虑,OSPF也使用了认证,OSPF同时支持明文和MD5认证,在启用OSPF认证后,Hello包中将携带密码,双方Hello包中的密码必须相同,才能建立OSPF邻居关系,需要注意,空密码也是密码的一种。

当OSPF邻居的一方在接口上启用认证后,从该接口发出的Hello包中就会带有密码,双方的Hello包中拥有相同的密码时,邻居方可建立;一台OSPF路由器可能有多个OSPF接口,也可能多个接口在多个OSPF区域,只要在接口上输入OSPF认证的命令后,便表示开启了OSPF认证,可以在每个接口上一个一个启用,也可以一次性开启多个接口的认证,如果需要开启多个接口的认证功能,那么认证的命令就并非直接在接口上输入,而是到OSPF进程模式下输入,并且是对某个区域全局开启的,当在进程下对某个区域开启OSPF认证后,就表示在属于该区域的所有接口上开启了认证。所以,在进程下对区域配置认证,是快速配置多个接口认证的方法,与在多个接口上一个一个开启,没有本质区别。因为OSPF虚链路被认为是骨干区域的一个接口,一条链路,所以在OSPF进程下对骨干区域开启认证后,不仅表示开启了区域0下所有接口的认证,同时也开启了OSPF虚链路的认证,但OSPF虚链路在建立后,并没有Hello包的传递,所以认证在没有重置OSPF进程的情况下,是不会生效的。

OSPF汇总路由

OSPF RFC (1583)并没有规定一个区域适合多少台路由器,一个网段多少个邻居,或如何布署网络。

配置OSPF实验

ospf_experiment1.png
ospf_experiment1.png

  • OSPF邻居
  • OSPF LSA
  • OSPF虚链路
  • OSPF认证

ospf_experiment2.png
ospf_experiment2.png

  • OSPF外部路由
  • OSPF路由汇总
  • OSPF末节区域
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/198440.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午3:13
下一篇 2026年3月26日 下午3:13


相关推荐

  • Delphi XE5如何读写INI文件

    Delphi XE5如何读写INI文件首先usesinifiles然后写文件procedureTHolidaySet.Button2Click(Sender:TObject);varIniFile:TIniFile;Count:Integer;begintryIniFile:=TIniFile.Create(TP…

    2022年7月18日
    19
  • wasserstein 距离

    wasserstein 距离注明 直观理解而已 正儿八经的严谨证明看最下面的参考 EarthMover sDistance 推土机距离的例子 有一堆土的分布是 PrPrP r 其随机变量是 xxx 现在要求把这堆土挪动成为分布 PgPgP g 其随机变量是 yyy 图上是 P P P theta 这样做的方法很多 那么做最小功的挪动该是什么 这是一个优化问题对应着的最优解是 这里 Pr Pg

    2026年3月18日
    2
  • 呼叫中心坐席功能都有哪些?

    呼叫中心坐席功能都有哪些?IPCC是IP呼叫中心(IPCallCenter)的简称,本质上是以IP技术和IP语音为主要应用技术的呼叫中心构建方式,即利用IP传输网来传输与交换语音、图像和文本等信息。(摘自百度百科)

    2022年6月30日
    30
  • 安卓手机上超好用的4款C语言IDE(附下载地址)

    安卓手机上超好用的4款C语言IDE(附下载地址)**如果找不到这几款编译器的可以联系我,我发给你QQ:1873564884**电脑有时太麻烦,不方便随时运行测试结果,手机上有不少编译器,子曰:“工欲善其事,必先利其器”。拥有一款好的编译器也是成功的一部分。话不多说让我们来看看。1:C4droid汉化版这款相信大家一定听说过,毕竟我原来也用过,感觉很菜,点击编译后没反应,上网查找说要安装gcc插件,而且要自己要自己找安装目…

    2022年5月6日
    155
  • type="button" ,"submit" 的区别(转)

    type="button" ,"submit" 的区别(转)

    2021年9月13日
    63
  • JSON教程[通俗易懂]

    JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLanguage, StandardECMA-2623rdEdition-December1999的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C,C++,…

    2022年4月6日
    120

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号