计网五层教学模型中网络层IPv4协议相关
本文仅简单介绍教学用五层模型中网络层的IPv4协议相关知识点
计网五层教学模型中网络层IPv4协议相关
一、关于网络层
- 在教学用五层模型中,网络层负责实现主机与主机间的数据分组的以IP地址为标识的传输,其依赖下层数据链路层实现的节点与节点间(包括中间的路由器、交换机等)的数据帧的以MAC地址为标识的传输,此外该层还主要实现
- 异构网络互联(拓扑结构、物理或链路层实现、主机类型不同)
- 路由与转发(多个路由器间相互配合,规划数据分组的最佳转发路径)
- 拥塞控制(网络上出现超负荷的数据分组时易导致吞吐量反而降低的现象,这是考虑到多个主机的宏观控制,不同于流量控制属于只考虑两节点间数据帧的收发窗口匹配的相对微观控制)
- 每个IP地址为$32$比特编码,其常被拆分为四个$8$比特二进制编码,然后分别转换为十进制数以点分隔进行表示,例如
59.175.49.153
形式,故其每部分十进制数范围为$[0, 255]$
1
2
00111011 10101111 0110001 10011001
59 .175 .49 .153
二、IPv4协议
2.1 IP分组的结构
2.1.1 IP分组的长度
- IP(Internet Protocol)协议是互联网的核心,其依赖于链路层的相关协议,定义了IP分组即IP数据报(通过路由器进行存储与转发),每个IP分组可承载
- 上层传输层的TCP、UDP协议传下来的数据
- 同层网络层的ICMP、IGMP协议的数据
- 每个IP分组由首部(包含固定的$20$字节和可变的$40$字节两部分)和数据部分组成
- 版本($4$比特编码):区分IPv4还是IPv6
- 首部长度($4$比特编码):限制首部的长度为$[0,15]\times 4$字节
- 总长度($16$比特编码):限制首部与数据部分的从长度为$[0,65535]\times 1$字节
- IP分组首部还包含以下信息
- 生存时间($8$比特编码):IP分组经路由器转发的次数最多为有限TTL次,通常由源主机设置,若在有限次数内未抵达目标主机,则丢弃并回传ICMP报文通知异常
- 协议($8$比特编码):为TCP协议服务则为$6$,为UDP协议服务则为$17$,使得接收方知晓应当将该IP分组递交给上层的哪个协议
- 首部检测和($16$比特编码):检测首部的差错(网络层不检测数据部分的差错),若全为$0$则无需校验,其校验计算方法与UDP一致(参考后文)
- 源地址($32$比特编码):发送方的IP地址
- 目的地址($32$比特编码):接收方的IP地址
2.1.2 IP分组的分片
- 一个链路层数据帧能承载的最大数据量称为最大传输单元(MTU, Maximum Transmission Unit),如以太网的MTU为$1500$字节(在链路层章节中提到过数据帧存在最短帧长和最长帧长的限制,以太网最长$1518$字节)
- 当一个IP分组的总长度超出了当前IP协议所依赖链路的MTU大小,则需要被分片,即把这个长分组拆分为若干小分片,每个分片被添上IP首部成为一个新的独立IP分组进行传输(每个分片被独立路由转发,可能走不同路径,提升了传输效率)
2.1.3 IP分组的重组
- 分片后的数据分组到达目的主机后需要被重组,这需通过IP首部中的其它字段实现
- 标识($16$比特编码):标识该IP分组(可能是分片)从属于哪个原始IP分组
- 标志($3$比特编码):标志该IP分组的性质
- 最低位(MF, More Fragment)为$1$表示并非最后一个分片,$0$表示是最后一个
- 次低位(DF, Don’t Fragment)为$1$表示不允许被分片,$0$表示允许(若路由器接收到一个不允许分片的IP分组,且下一段链路的MTU短于该IP分组,则路由器会将该IP分组丢弃,然后回传发送方一个ICMP报文通知异常)
- 片偏移($13$比特编码):表示该IP分组在被分片前的原始IP分组中的字节位置,其表示的长度为$8$字节的整数倍
- 前文的例子中,我们可以观察原始IP分组及其分片的标识、标志、片偏移信息
2.2 IPv4地址设计
2.2.1 地址分类
- 在IPv4刚发明时互联网并未推广至民用,当时只设计了$32$比特IP地址($2^{32}\approx 42亿$),即只能保证约$42亿$个独特主机(这在现在看来是完全不够用的),这种设计将地址分为了ABCDE共五类(其中ABC类属于单播地址,D类属于多播地址,E类是当时留下的待定义部分)
- 该设计下的IP地址被分为
(网络号,主机号)
的两级结构,ABCDE五类IP地址由网络号的长度进行区分,而网络号长度由其前几比特决定 - $32$比特的IP地址被等分为$4$个$8$比特的部分,并转化为十进制方便人类阅读,而由于网络号前几比特(即第一个$8$比特部分的最高几位)对应独特的种类,其会限制由$4$个十进制数表示的IP地址的第一个十进制数的范围
- A类:$[0]…….$限制第一个十进制数在$[1,126]$范围内($0$和$127$有特殊用途)
- B类:$[10]……$限制第一个十进制数在$[128,191]$范围内
- C类:$[110]…..$限制第一个十进制数在$[192,223]$范围内
- D类:$[1110]….$限制第一个十进制数在$[224,239]$范围内
- E类:$[1111]….$限制第一个十进制数在$[240,255]$范围内
- 该设计下的IP地址被分为
2.2.2 地址使用
- 若一个公司申请了ABC类之一的单播网络号
- 公司的所有主机都使用相同的网络号(这些主机属于同一个网络,若同网络内的某主机的网络号不符设定,则其就不能在该网络内正常使用)
- 主机号则用于区分公司内的不同主机,其与网络号共同标识了全球唯一的主机IP地址
- 每个主机都配置有默认网关(即IP分组默认发往的路由器IP地址),该主机接入互联网时,对于其发出的IP分组
- 若目的IP地址不是当前网络,则IP分组会默认被发送到默认网关对应的路由器上(网络层通过ARP协议找到IP地址对应的链路层MAC地址)等待路由转发处理,每个路由器缓存一个转发表,表项为
(目的网络号,转发接口)
映射 - 若目的IP地址位于当前网络,则IP分组不会被发往默认网关对应的路由器,而是直接通过交换机、集线器等直接发往目的IP地址经ARP协议转换后对应的MAC地址处
- 若目的IP地址不是当前网络,则IP分组会默认被发送到默认网关对应的路由器上(网络层通过ARP协议找到IP地址对应的链路层MAC地址)等待路由转发处理,每个路由器缓存一个转发表,表项为
2.2.3 特殊地址
- 有以下几种特殊的IP地址仅用于特殊用途,而不能被指派给网络中任意主机或路由器私用
- 网络号为$Y$而主机号全为$0$的地址
<Y,0>
- 仅用于标识该网络$Y$本身(用于路由表/转发表)
- 不能作为源地址或目的地址
- 网络号全为$0$而主机号为$X$的地址
<0,X>
- 仅用于标识本网络中的$X$主机(用于发送IP分组)
- 仅能作为源地址
- 网络号全为$0$且主机号为$0$的地址
<0,0>
- 仅用于标识本网络中的本主机(当主机刚接入网络时,其并不拥有IP地址,故其会以
<0,0>
源地址和<1,1>
目的地址广播一个DHCP报文,当DHCP服务器接收到该报文时就会为该主机分配一个IP地址) - 仅能作为源地址
- 仅用于标识本网络中的本主机(当主机刚接入网络时,其并不拥有IP地址,故其会以
- 网络号为$Y$而主机号全为$1$的地址
<Y,1>
(故在一个网络中,若主机号占$n$比特,那么最多能被唯一标识的主机数量为$2^n-2$个)- 仅用于向网络$Y$发送广播IP分组
- 仅能作为目的地址
- 网络号全为$1$且主机号为$1$的地址
<1,1>
- 仅用于向本网络发送广播IP分组(包括默认网关)
- 仅能作为目的地址
- 网络号为$127$而主机号为正常数的地址
<127,X>
(任何非全$0$或非全$1$的数)- 环回自测地址,表示主机本身,用于本地软件环回测试(例如游戏开发的客户端和服务端在本地进行测试,就需将数据包发送到本地)
- 既能作为源地址也能作为目的地址
- 网络号为$Y$而主机号全为$0$的地址
2.3 子网划分与掩码
2.3.1 子网划分的概念
- 对于IPv4中的某类IP地址,例如B类地址的网络号和主机号各占$16$比特,占有该网络号的组织很难将所有$(2^{16}-2)$种主机号全部分配完
- 子网划分技术可将同一网络号对应的网络再划分为若干子网,例如下图中借用主机号的比特位进行标识,划分了两个子网(对应学校的不同校区)
- 这样做能提高IP地址编码的利用率,将原本不会被用到的比特位用来为该网络内的主机进行分类(即划归不同子网)
- 子网划分后的IP地址从
<网络号,主机号>
变为了<网络号,子网号,主机号>
三级结构
- 不同的$k$个子网内的主机群会被接入到所属网络的路由器的$k$个对应端口上
- 若想划分更多子网则取用更多比特位设计子网号即可,对于原本的$n$比特主机号
- 可从中抠出$m$比特作为子网号,用以标识最多$2^m$个子网
- 每个子网包含的IP地址数量均为$(2^{n-m}-2)$,因为子网主机号的全$0$标识子网本身,全$1$标识主机本身,参考不划分子网的IP地址中的特殊地址
2.3.2 子网掩码的概念
- 划分子网前,主机仅需具备IP地址并配置默认网关IP地址即可,而划分子网后,主机和传输设备的网络层功能就需要进行适配扩展,为此需要配置子网掩码
x.x.x.x
(即$32$比特的二进制编码,和IP地址一样等分为$4$部分后转换为十进制进行表示)
- 子网验码的作用是和IP地址进行逐位与运算以得到网络号和子网号
- 该网络内所有主机和与子网相连的路由器端口都需配置相同的子网掩码,以$16$比特的网络号和$1$比特的子网号地址为例,子网掩码为
255.255.128.0
即$17$位$1$和$15$位$0$ - 将子网掩码与IP地址逐位相与,就能将网络号和子网号共$17$位编码保留下来,而剩下的$15$位主机号都会被子网掩码的末尾$15$位$0$做与运算筛掉变为全$0$,此时由于已知IP地址为网络号$16$位的B类地址,就能同时得到网络号和子网号
- 该网络内所有主机和与子网相连的路由器端口都需配置相同的子网掩码,以$16$比特的网络号和$1$比特的子网号地址为例,子网掩码为
1
2
11111111 11111111 10000000 00000000
255 .255 .128 .0
2.3.3 子网的路由转发
- 对于不支持子网划分的路由器,其转发表只需记录目的网络号和转发接口即可,而对于支持子网划分的路由器,其转发表还需记录子网掩码属性
- 子网内的主机发送IP分组时,其源IP地址、目的IP地址的网络号和子网号会被检测是否同时相等(通过子网掩码的出这两部分编号以进行比较)
- 若二者均相等,则无需将IP分组传给默认网关路由器,直接在子网内部分发即可
- 若网络号相等但子网号不等(IP分组封装成帧过程中同样以ARP协议获取MAC地址)
- 先将IP分组封装成帧,发送给默认网关,默认网关路由器接收帧序列后,将其拼装回IP分组
- 若目的IP地址与转发表中的表项相匹配(将目的IP地址与各表项的子网掩码进行按位与,结果若与该表项的目的IP地址相同,则匹配成功),则再次将IP分组封装成帧转发到对应的子网端口处
- 若网络号不等,则需经默认网关路由器转发到其它网络对应的端口处
- 若目的IP地址所在网络不支持子网划分,则路由器处会为该转发表项根据其类型设置默认子网掩码,例如A类对应
255.0.0.0
、B类对应255.255.0.0
、C类对应255.255.255.0
,以保证无论支持子网划分与否,网络间相互兼容 - 若在转发表中的所有表项均不匹配,则IP分组会被从默认路由表项处转发出去
- 若目的IP地址所在网络不支持子网划分,则路由器处会为该转发表项根据其类型设置默认子网掩码,例如A类对应
2.4 无分类编址CIDR
2.4.1 CIDR技术引入
- 一个组织需要若干主机时,用C类地址只有$2^8-2$的地址空间,而B类有$2^{16}-2$的地址空间,前者太少而后者过多导致浪费,可见分类编址之不灵活
- 所以后来引入了无类别域间路由(CIDR, Classless Inter-Domain Routing)的无分类编址
2.4.2 CIDR编址格式
- CIDR规定的$32$比特IP地址同样分为
<网络前缀,主机号>
两部分,但其中网络前缀
长度可变 - 例如某公司需$2000$台主机,则IP地址管理机构可为该公司分配一个$21$比特网络前缀的CIDR地址块,则主机地址空间为$2^{11}=2048$不大不小正好够用,其CIDR地址记为如下形式
- 符号
/
前代表IPv4地址 - 符号
/
后代表子网掩码(其指定子网掩码$1$的位数,也就确定了子网掩码本身)
- 符号
1
十进制数.十进制数.十进制数.十进制数/21
2.4.3 CIDR子网划分
对于一个CIDR地址块,其也可被划分为多个子网,主要有定长与变长两种子网划分方法
2.4.3.1 定长子网划分
- 定长子网划分与传统子网划分同理,将主机号前$k$比特作为定长子网号,划分出$2^k$个子网,故每个子网包含的地址块大小相同,这样不灵活导致会浪费有限IP空间(无法分出非$2$幂次数量个的子网,且并不是每个子网都需要同样大小的地址空间)
2.4.3.2 变长子网划分
- 变长子网划分中的子网号长度可变,故每个子网包含的地址块大小不同,划分更灵活,如下图所示可以根据地区人口划分合理大小的CIDR地址块
- 下级机构可从上级ISP申请更小的CIDR地址块,如下图所示类似地继续细分下去,这样的划分方式与哈夫曼树与哈夫曼编码本质上相似
- 上述划分示例的路由转发示意如下,若传入IP分组的目的地址为
128.14.32.153
,其会被128.14.32.152/30
匹配,因128.14.32.153
落在[128.14.32.152, 128.14.32.155]
地址块范围内
- 可以看出上述树结构越往下层,对IP地址总数的浪费越多,所以对于同样的$m$比特可自由分配的主机号,若想划分出$p$个子网(即$p$个叶子节点)且使得总IP地址数尽可能多,就需要让树高尽可能降低(反之求最小IP地址总数则需让树尽可能深,如下图例题所示)
2.4.4 CIDR路由聚合
- 对于一个路由器的转发表,可以将其转发接口相同且部分网络前缀也相同的表项聚合为一条表项,这称为路由聚合或构成超网
- 其好处是能缩小路由表(节省存储空间),并提升查询效率(降低转发时延)
- 其坏处是会引入额外的无效地址,且同一个IP地址可能会匹配多个表项
- 对于同一个IP地址匹配多个转发表项的情况,需遵循最长前缀匹配原则,保证转发效率
2.4.5 综合前文技术
- 前文所述的几种网络组织技术相互间是兼容的,参考下图
2.5 网络地址转换NAT
2.5.1 公网私网IP
- 即便前文CIDR等技术提高了IPv4地址的利用率,但IPv4地址的总数有限$2^{32}$个,每个设备消耗一个IP地址迟早会耗尽,故引入网络地址转换(NAT, Network Address Translation)技术作为缓兵之计,在理解NAT技术前需先理解端口号
- 链路层实现了节点到节点间的通信(MAC地址标识链路中的节点)
- 网络层实现了主机到主机间的通信(IP地址标识不同的主机)
- 传输层通过引入端口号实现了进程到进程间的通信(端口号标识主机上不同进程,不同主机内进程对应的端口号可能在数值上相等)
- NAT的思路是让一组主机共享同一个公网IP地址以减少IP地址的消耗,例如家庭/学校局域网内所有主机共享相同公网IP地址
- 局域网对内通过为不同主机分配私网IP进行区分标识
- 局域网对外通过端口号标识局域网内某主机的特定进程
- 关于公网IP地址与私网IP地址
- 公网IP(外网IP)地址指的是一个局域网从ISP获取的全球唯一的IP地址,用于该局域网与外界进行通信
- 私网IP(内网IP)地址指的是局域网内自行分配的可复用IP地址,用于标识局域网内的不同主机,仅需局域网内唯一而无需全球唯一
2.5.2 NAT路由器
- 数据从外部网络根据公网IP传到对应NAT路由器上时,NAT路由器会从NAT表映射得到其目的去往主机的私网IP地址,反之从NAT网路内向外发送数据时则需将私网IP替换为公网IP
- 不同局域网内的设备相互发送数据时,发送方无法知晓对方设备的内网IP、以及与自己通信的进程的内网对应端口号,其只能知晓对方所处局域网外网对外暴露的公网IP和公网端口号信息并将其作为目的地址,发送时也需要发送地址从私网IP与端口替换为公网版本
- 例如下图种的右侧手机与左侧手机进行微信通信,前者微信进程只能通过腾讯服务器查询后者微信进程对应的公网IP与端口号
4096
作为目的地址
2.6 地址解析协议ARP
2.6.1 ARP分组与ARP表
- ARP协议用于在同一局域网内部,查询IP地址与MAC地址间的映射关系(每个主机至少有一个由网络适配器提供的MAC地址,每个路由器有多个转发接口,即对应多个MAC地址)
- 网络层的不同协议使用的数据分组是不同的
- IP协议对应的PDU是IP分组
- ARP协议对应的PDU是ARP分组
- 回顾链路层章节所介绍的DixEthernetV2标准下的MAC帧结构中,存在协议类型字段
- 其目的是标识该帧存储的上层网络层的PDU类型,如IP分组或ARP分组
- 不同类型的数据分组在封装成若干MAC帧时,会在每帧中标识自身协议类型
- 存储在ARP缓存中的ARP表是一个记录IP地址与MAC地址间映射关系的数据结构,每台主机和路由器都拥有自己的ARP表,其表项初始时为空,需被定期更新
2.6.2 ARP请求与ARP响应
- 由于ARP表初始为空,需设法将映射关系表项填入表中,发送方需广播ARP请求分组
- 该ARP分组所携带的信息(即网络层PDU)包括
- 发送方的IP地址
X
与MAC地址Y
(用于使得接收方缓存自己的映射) - 目的接收方的IP地址
Z
(发送方只知其IP地址,现需获取其MAC地址)
- 发送方的IP地址
- 该ARP分组被封装成对应类型的MAC帧
- 目的地址编码为全
1
而源地址为Y
,代表这是自己发送的广播帧
- 目的地址编码为全
- 该ARP分组所携带的信息(即网络层PDU)包括
- 若同局域网内的目的IP地址的主机收到了广播的ARP请求分组,就会回传ARP响应分组
- 该ARP分组所携带的信息(即网络层PDU)包括
- 自身的IP地址
Z
与MAC地址V
(由于可能存在集线器这种无脑广播的家伙,其可能将回传的ARP响应分组发给错误的对象,所以此处回传时也要提供自身IP地址信息用于检测接收方是否是正确的对象)
- 自身的IP地址
- 该ARP分组被封装成对应类型的MAC帧
- 目的地址编码为
Y
而源地址为V
,代表这是自己回传的单播帧
- 目的地址编码为
- 该ARP分组所携带的信息(即网络层PDU)包括
- 以一个例子理解请求响应的流程,假设下图中的H3主机想要向外部网络发送数据,初始状态下其知晓默认网关的IP地址但不知其MAC地址
- 故需要先封装一个ARP请求分组广播出去,不出意外会得到默认网关处回传的ARP响应分组,在这个过程中有两处ARP表发生了更新
- 接收方路由器收到ARP请求分组时,会将发送方IP-MAC映射存入自己ARP表中
- 发送方主机收到ARP响应分组后,会将接收方IP-MAC映射存入自己ARP表中
- 此时主机H3已知晓默认网关映射,就能通过MAC地址将数据发送到路由器,继而发送到目的外部网络(且当从外部网络想要向H3发送数据时,由于路由器的ARP表也缓存了相关映射,就可以直接发送而无需再次使用ARP请求响应)
- 故需要先封装一个ARP请求分组广播出去,不出意外会得到默认网关处回传的ARP响应分组,在这个过程中有两处ARP表发生了更新
2.7 动态主机配置协议DHCP
前文讲到的所有讨论都是建立在我们已经知晓了主机和路由器的IP地址、子网掩码、默认网关等信息的基础之上的,但在主机刚接入网络中时并不具备上述参数,该怎么办呢?
2.7.1 DHCP协议引入
- 动态主机配置协议(DHCP, Dynamic Host Configuration Protocol)是应用层的协议,用于初始化主机的IP地址、子网掩码、默认网关等网络相关参数
- DHCP协议使用传输层的UDP协议提供的服务,后者使用网络层的IP协议提供的服务,后者使用链路层的某种协议提供的服务,这样逐层向下封装以进行传输
2.7.2 DHCP工作流程
- 不同子网持有的CIDR块的有效IP地址(当然不包括全
0
或全1
主机号的特殊IP地址)均由自己的一个或多个DHCP服务器负责分配(家庭网络中一般由家庭路由器兼职DHCP服务器)
- 假设一个新主机H3要接入上图中的网络中,其此时只拥有自身MAC地址,而未配有IP地址、子网掩码、默认网关等
- 主机接入网络的初始化流程总体分为四个步骤,各对应一种报文(所有报文均被以UDP协议进行封装,然后再由网络层封装为IP分组、由链路层封装为MAC帧)
- 这些初始化操作由主机H3上的DHCP客户端进程(端口
68
)、DHCP服务器上的DHCP服务端进程(端口67
)完成
- 第一步:主机H3向DHCP服务器发送DISCOVER(发现)报文
- 应用层报文内容
- 主机H3自身的MAC地址
- 传输层UDP段内容
- 源端口号(主机H3自身的端口号)
- 目的端口号(DHCP服务器专用端口号
67
,其它主机不会有相同端口号)
- 网络层IP分组内容
- 特殊源IP地址(
<0,0>
用于表示自己未被初始化,专门用于DHCP协议) - 特殊目的IP地址(
<1,1>
表示IP分组是广播分组,因不知DHCP服务器IP地址)
- 特殊源IP地址(
- 链路层MAC帧内容
- 源MAC地址(主机H3自身的MAC地址)
- 目的MAC地址(
48
比特全为1
表示是广播帧)
- 应用层报文内容
- 第二步:DHCP服务器向主机H3发送OFFER(提供)报文
- 应用层报文内容
- 为主机H3分配的IP地址
- 为主机H3配置的子网掩码、默认网关
- 租用期大小(每台主机的IP地址都有使用期限,到期需续租)
- 传输层UDP段内容
- 源端口号(DHCP服务器自身的端口号
67
) - 目的端口号(先前接收发现报文时获知的主机H3客户端进程的端口号)
- 源端口号(DHCP服务器自身的端口号
- 网络层IP分组内容
- 源IP地址(DHCP服务器自身的IP地址)
- 特殊目的IP地址(
<1,1>
表示IP分组是广播分组,因主机H3还未使用IP地址)
- 链路层MAC帧内容
- 源MAC地址(DHCP服务器自身的MAC地址)
- 目的MAC地址(先前接收发现报文时获知的主机H3的MAC地址,是单播帧)
- 应用层报文内容
- 第三步:主机H3向DHCP服务器发送REQUEST(请求)报文
- 应用层报文内容
- 主机H3自身的MAC地址
- 主机H3从提供报文中分配到的IP地址
- 传输层UDP段内容
- 源端口号(主机H3自身的端口号)
- 目的端口号(DHCP服务器专用端口号
67
)
- 网络层IP分组内容
- 特殊源IP地址(
<0,0>
表示自身未正式采用分配的IP地址,需等待确认报文) - 特殊目的IP地址(
<1,1>
表示IP分组是广播分组)
- 特殊源IP地址(
- 链路层MAC帧内容
- 源MAC地址(主机H3自身的MAC地址)
- 目的MAC地址(
48
比特全为1
表示是广播帧)
- 应用层报文内容
- 看到这里会产生疑问:为何在第二步中的提供报文中,DHCP服务器不能提供其自身的IP地址和MAC地址呢,而导致第三步中仍然只能发送广播IP分组和广播帧?
- 因为在大型子网中可能存在多个DHCP服务器负责管理不同范围的IP地址分配,在这种情况下新接入主机发送的DISCOVER报文会被全部DHCP服务器接收
- 所以主机会收到多个OFFER报文,因此此时主机必须再次广播告诉所有服务器自己选用了哪个OFFER
- 第四步:DHCP服务器向主机H3发送ACKNOWLEDGE(确认)报文
- 被选中的DHCP回传该报文,内容和第二步的提供报文完全一致
- 类比应聘来看,第一步是应聘者请求录用,第二步是公司发录用意向Offer,第三步是应聘者通知公司确认接受Offer与否(其手中可能有多个公司Offer,需择一入职),第四步是公司发正式录用Offer
本文由作者按照 CC BY-NC-SA 4.0 进行授权