【网络】传输层TCP协议 | 三次握手 | 四次挥手

目录

一、概述

2.1 运输层的作用引出

2.2 传输控制协议TCP 简介

2.3 TCP最主要的特点

2.4 TCP连接

二、TCP报文段的首部格式

三、TCP的运输连接管理

3.1 TCP的连接建立(三次握手)

3.2 为什么是三次握手?

3.3 为何两次握手不可以呢?

3.4 TCP的连接释放(四次挥手)

3.5 为什么客户端在TIME-WAIT状态必须等待2MSL的时间呢?

3.6 TCP连接状态解释


【网络】网络层IP地址和IP数据报的格式

【网络】网络层协议ARP和IP协议转发流程

【网络】计算机网络基础概念入门

【网络】网络层ICMP协议-CSDN博客

【Linux】网络诊断 traceroute命令详解

 【Linux】nc 网络诊断 | 文件传输 命令详解


一、概述


从通信和信息处理的角度看,传输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两台主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。

1.1 运输层的作用引出


如下图,假设局域网LAN1上的主机A和局域网LAN2上的主机B通过互连的广域网WAN进行通信。我们知道,IP协议能够把源主机A发送出的分组,按照首部中的目的地址,送交到目的主机B,那么,为什么还需要运输层呢 ?

从IP层来说,通信的两端是两台主机。严格地讲,两台主机进行通信就是两台主机中的应用进程互相通信。IP协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。从运输层的角度看,通信的真正端点并不是主机而是主机中的进程。也就是说,端到端的通信是应用进程之间的通信。

运输层提供应用进程间的逻辑通信”。“逻辑通信”的意思是:从应用层来看,只要把应用层报文交给下面的运输层,运输层就可以把这报文传送到对方的运输层(哪怕双方相距很远,例如几千公里),好像这种通信就是沿水平方向直接传送数据。但事实上这两个运输层之间并没有一条水平方向的物理连接。数据的传送是沿着图中的虚线方向(经过多个层次)传送的。

从这里可以看出网络层和运输层有明显的区别。网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信(如下图)。

1.2 传输控制协议TCP 简介


(TCP协议)传输控制协议是一种面向连接的、可靠的、基于字节流的方式进行有序的无差错的数据传输通讯协议,它负责完成传输层所指定的功能,利用重发技术和拥塞控制机制,向应用程序提供可靠的通信连接,使它能够自动适应网上的各种变化。比如:数据报检测、流量控制、拥塞控制、数据排序、超时重发等。

1.3 TCP最主要的特点


TCP是TCP/IP体系中非常复杂的一个协议。下面介绍TCP最主要的特点。

(1)TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。也就是说,应用进程之间的通信好像在“打电话”:通话前要先拨号建立连接,通话结束后要挂机释放连接。

(2)每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的(一对一)。

(3)TCP提供可靠交付的服务通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。

(4)TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。

(5)面向字节流TCP中的“流”(stream)指的是流入到进程或从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义。TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块就把收到的字节流交付上层的应用程序)。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

1.4 TCP连接


每一条TCP连接有两个端点。那么,TCP连接的端点是什么呢?TCP连接的端点叫做套接字(socket)或插口。 定义:端口号拼接到(concatenated with)IP地址即构成了套接字。因此,套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。例如,若IP地址是192.3.4.5而端口号是80,那么得到的套接字就是(192.3.4.5:80)。

套接字 socket = I P 地址 + port 端口号 = socket IP 地址 + port端口号

TCP连接 = {socket1, socker2} = {(IP1, port1), (IP2, port2)}

总之,TCP连接的端点是个很抽象的套接字,即(IP地址:端口号)。也应记住:同一个IP地址可以有多个不同的TCP连接,而同一个端口号也可以出现在多个不同的TCP连接中。


二、TCP报文段的首部格式


TCP报文段首部的前20个字节是固定的如下图,后面有4n字节是根据需要而增加的选项(n是整数)。因此TCP首部的最小长度是20字节。

部固定部分各字段的意义如下:

(1)源端口和目的端口 各占2个字节,分别写入源端口号和目的端口号,TCP的分用功能也是通过端口实现的。

(2)序号 占4字节。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。序号范围是[0,232–1],共232(即4 294 967 296)个序号。序号增加到232–1后,下一个序号就又回到0。也就是说,序号使用mod 232运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号字段值是301,而携带的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的名称也叫做“报文段序号”。

(3)确认号 占4字节是期望收到对方下一个报文段的第一个数据字节的序号。例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。请注意,现在的确认号不是501,也不是700,而是701。

总之,应当记住:

若确认号=N,则表明:到序号N–1为止的所有数据都已正确收到。

由于序号字段有32位长,可对4GB(即4千兆字节)的数据进行编号。在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了。

(4)数据偏移 占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。但应注意,“数据偏移”的单位是32位字(即以4字节长的字为计算单位)。由于4位二进制数能够表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大长度(即选项长度不能超过40字节)。

(5)保留 占6位,保留为今后使用,但目前应置为0。

下面有6个控制位,用来说明本报文段的性质,它们的释义见下面的(6)~(11)。

(6)紧急URG(URGent) 当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行。因此用户从键盘发出中断命令(Control+C)。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了许多时间。

当URG置1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。

(7)确认ACK(ACKnowledgment) 仅当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1。

(8)推送PSH(PuSH) 当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。

虽然应用程序可以选择推送操作,但推送操作很少使用。

(9)复位RST(ReSeT) 当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。RST也可称为重建位或重置位。

(10)同步SYN(SYNchronization) 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文。关于连接的建立和释放,在后面的5.9节还要进行详细讨论。

(11)终止FIN(FINis,意思是“完”、“终”) 用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。

(12)窗口 占2字节。窗口值是[0,216–1]之间的整数。窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。

例如,发送了一个报文段,其确认号是701,窗口字段是1000。这就是告诉对方:“从701号算起,我(即发送此报文段的一方)的接收缓存空间还可接收1000个字节数据(字节序号是701~1700),你在给我发送数据时,必须考虑到这一点。”

总之,应当记住:窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化着。

(13)检验和 占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式与图5-5中UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6),把第5字段中的UDP长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用IPv6,则相应的伪首部也要改变。

(14)紧急指针 占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。因此,紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗


三、TCP的运输连接管理


TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即:连接建立、数据传送和连接释放。运输连接的管理就是使运输连接的建立和释放都能正常地进行。

在TCP连接建立过程中要解决以下三个问题:

(1)要使每一方能够确知对方的存在。

(2)要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。

(3)能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。

TCP连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户(client),而被动等待连接建立的应用进程叫做服务器(server)。

3.1 TCP的连接建立(三次握手)


TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段。下图为客户端主动发起的图解:

首先主动打开连接的客户端结束CLOSED状态,被动打开的服务器端也结束CLOSED状态,并进入LISTEN状态。随后开始“三次握手”:

  1. 客户端进程首先创建传输控制模块TCB(Transmission Control Block)。然后,客户端向服务端发出连接请求报文段。这时首部中的同步位SYN=1,初始序号seq=x。这时,TCP客户进程进入SYN-SENT(同步已发送)状态。
  2. 服务端收到连接请求报文段后,如同意建立连接,则向客户端发送确认。在确认报文段中把标志位SYN位和ACK位都置1,表示“已收到请求并同意创建新连接;确认号是ack=x+1,表示将来自客户端的报文序号seq值加1作为自己确认号ack的值;初始序号seq=y。请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。这时TCP服务器进程进入SYN-RCVD(同步收到)状态。
  3. 客户端收到服务端的确认后,还要向服务端给出确认。标志位为ACK=1,表示“已收到同意连接的信号”;而自己的序号seq=x+1,表示将来自服务端的确认号ack值作为自己的序号值;确认号为ack=y+1,表示将来自服务端序号seq值加1作为自己的确认号ack的值。TCP的标准规定,ACK报文段可以携带数据。但如果不携带数据则不消耗序号,在这种情况下,下一个数据报文段的序号仍是seq=x+1。这时,TCP连接已经建立,客户端进入ESTABLISHED(已建立连接)状态,服务端收到来自客户端的确认连接TCP报文之后,也确认了双方间数据传输正常,结束SYN-RCVD状态,进入ESTABLISHED状态。

3.2 为什么是三次握手?


首先要明确下TCP握手的目的是为了通信,能够完成数据传输。那么通信的前提就是客户端和服务端都要具备读写能力。

第一次握手: 服务端收到客户端发来的请求(即第一次握手)能够证明客户端具备写的能力,

第二次握手:服务端给客户端进行回复信息(即第二次握手),客户端收到服务端回复的信息能够证明服务端具备读写的能力;

第三次握手:客户端发送给服务端最后一段报文(即第三次握手),服务端收到后能够证明客户端具备读的能力。

3.3 为何两次握手不可以呢?


原因是为了防止服务端开启一些无用的连接增加服务器开销以及防止已失效的连接请求报文段突然又传送到了服务端而产生错误。“第三次握手”是客户端向服务端发送数据,目的是告诉服务器,客户端有没有收到服务器“第二次握手”时传过去的数据,若发送的是“收到了”的信号,服务端接收后就正常建立TCP连接,否则建立TCP连接失败,服务器关闭连接端口,由此减少服务器开销及防止接收到失效请求而导致错误

3.4 TCP的连接释放(四次挥手)


  1. 客户端向服务端发送释放连接TCP报文,并停止再发送数据主动关闭TCP连接。客户端把连接释放报文段首部的终止控制位FIN置1,其序号seq=u。这时客户端进入FIN-WAIT-1(终止等待1)状态,等待服务端的确认。
  2. 服务端收到连接释放报文段后即发出确认,标志位为ACK=1,表示“收到释放请求”;序列号为seq=v;确认号是ack=u+1,等于服务端前面已传送过的数据的最后一个字节的序号加1。服务端进入CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时应通知高层应用进程,因而从客户端到服务端这个方向的连接就释放了,这时的TCP连接处于半关闭(half-close)状态,即客户端已经没有数据要发送了,但服务端若发送数据,客户端仍要接收。也就是说,从服务端到客户端这个方向的连接并未关闭,这个状态可能会持续一段时间。
  3. 客户端收到来自服务端的确认后,就进入FIN-WAIT-2(终止等待2)状态。等待服务端发出的连接释放报文段。若服务端已经没有要向客户端发送的数据,其应用进程就通知TCP释放连接。这时服务端发出的连接释放报文段必须使FIN=1;标志位为FIN=1,ACK=1,表示“已准备好释放序号为seq=w。还必须重复上次已发送过的确认号ack=u+1。这时服务端就进入LAST-ACK(最后确认)状态,等待客户端的确认。
  4. 客户端在收到服务端的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK=1,确认号ack=w+1,而自己的序号是seq=u+1,确认号为ack=w+1,表示将来自服务端报文序号seq值加1作为自己的确认号ack的值。然后客户端进入到TIME-WAIT(时间等待)状态。请注意,现在TCP连接还没有释放掉。必须经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL后,客户端才进入到CLOSED状态。因此,从客户端进入到TIME-WAIT状态后,要经过4分钟才能进入到CLOSED状态,才能开始建立下一个新的连接。当客户端撤销相应的传输控制块TCB后,就结束了这次的TCP连接。

MSL即最长报文段寿命(Maximum Segment Lifetime),指任何报文在网络上存在的最长时间,超过该时间则报文被丢弃,一般MSL为30秒、1分钟等。

3.5 为什么客户端在TIME-WAIT状态必须等待2MSL的时间呢?


第一,为了保证客户端发送的最后一个ACK报文段能够到达服务端。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的服务端收不到对已发送的FIN+ACK报文段的确认。服务端会超时重传这个FIN+ACK报文段,而客户端就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着A重传一次确认,重新启动2MSL计时器。最后,客户端和服务端都正常进入到CLOSED状态。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样,服务端就无法按照正常步骤进入CLOSED状态。

第二,已失效的连接请求报文段”出现在本连接中。客户端在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

服务端只要收到了客户端发出的确认,就进入CLOSED状态。同样,服务端在撤销相应的传输控制块TCB后,就结束了这次的TCP连接。我们注意到,服务端结束TCP连接的时间要比A早一些。

3.6 TCP连接状态解释

字段

含义

CLOSED

关闭状态,表示当前主机没有正在运行的传输连接

LISTEN

监听状态,表示服务器正在等待新的传输连接进入

SYN-RCVD

表示主机已收到一个连接请求,但尚未确认

SYN-SENT

表示主机已经发出一个连接请求,等待对方确认

ESTABLISHED

传输连接建立,双方进入正常数据传输状态

FIN-WAIT-1

(主动关闭)主机已经发送关闭连接请求,等待对方确认

FIN-WAIT-2

(主动关闭)主机已收到对方关闭连接确认,等待对方发送关闭连接请求

TIMED WAIT

完成双向传输连接关闭,等待所有分组消失

CLOSING

双方同时尝试关闭传输连接,等待对方确认

CLOSE WAIT

(被动关闭)收到对方发来的关闭连接请求,并已确认

LAST ACK

被动关闭)等待最后一个关闭连接确认,并等待所有分组消失


TCP/IP协议、HTTP协议_tcp/ip http-CSDN博客

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

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

相关文章

STM32-电动车报警器

STM32-电动车报警器 1.振动传感器点亮LED灯 需求:当振动传感器接收到振动信号时,使用中断方式点亮LED1 //重写中断服务函数,如果检测到EXTI中断请求,则进入此函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {//一根中断线上接有多个…

leetcode刷题(剑指offer) 50.Pow(x, n)

50.Pow(x, n) 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。 示例 1: 输入:x 2.00000, n 10 输出:1024.00000示例 2: 输入:x 2.10000, n 3 输出&#x…

江科大stm32学习笔记5——蜂鸣器

目录 一、接线 二、代码部分 三、查看库函数的方法 一、接线 蜂鸣器选择有源高电平触发蜂鸣器。 GND——GND VCC——正极 I/O——B12 注意:32上的PA15、PB3、和PB4是默认调试端口,如果使用需要进行额外配置,一般避开这三个端口。 二、…

2024 年, Web 前端开发趋势

希腊哲学家赫拉克利特认为,变化是生命中唯一不变的东西。这句话适用于我们的个人生活、行业和职业领域。 尤其是前端开发领域,新技术、开发趋势、库和框架不断涌现,变化并不陌生。最近发生的一些事件正在改变开发人员构建网站和 Web 应用的方…

图像复原的天花板在哪里?SUPIR:开创性结合文本引导先验和模型规模扩大

SUPIR(Scaling-UP Image Restoration),这是一种开创性的图像复原方法,利用生成先验和模型扩大规模的力量。通过利用多模态技术和先进的生成先验,SUPIR在智能和逼真的图像复原方面取得了重大进展。作为SUPIR中的关键催化…

项目解决方案:市小区高清视频监控平台联网整合设计方案(上)

目 录 一、项目需求 1.1业务需求 1.2技术需求 1.3 环境要求 1.3.1 硬件要求 1.3.2 技术服务要求 二、系统设计方案 2.1 视频监控平台基础功能设计 2.2 视频资源及联网设备编码与管理设计 2.2.1 全省现有联网视频资源属性 2.2.2 视频资源编码具体格…

鸿蒙OS之Rust开发

背景 Rust是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust官方也使用Cargo工具来专门为Rust代码创建工程和构建编译。 OpenHarmony为了集成C/C 代码和提升编译速度,使用了GN Ninja的编译构建系统。GN的构…

认识产品经理 一个合格的产品经理 产品经理分类

目录 一.合格的产品经理 什么是产品 什么是产品经理 合格的产品经理 什么是产品?区别是? 什么是产品经理 合格的产品经理需要关注哪些核心问题? 二.产品经理分类 为什么会有不同类型 都有那些类型 根据不同类型的职责特点规划个人…

LAN安全及概念

实验大纲 一、终端安全 1.当前比较流行的网络攻击 2.常见的网络安全设备 3.终端受到攻击的主要途径 4.传统的基于主机的安全防护手段 二、访问控制 1.本地口令验证 2.AAA组成 3.身份验证 4.记账 5. 802.1X 三、第2层安全威胁 交换机攻击分类 四、MAC地址表 MAC地…

CC核心内容

目录 标准流: 盒子模型: 1.标准盒子模型 2.怪异盒子模型 浮动: 定位: 标准流、盒子模型、浮动、定位 Div是一个块级元素,span是内行元素 div元素通常用于创建一个独立的区块,它会单独占据一行或多行的空间 span元素通常用于包裹文本或内行元素&…

OpenGL/C++_学习笔记(四)空间概念与摄像头

汇总页 上一篇: OpenGL/C_学习笔记(三) 绘制第一个图形 OpenGL/C_学习笔记(四)空间概念与摄像头 空间概念与摄像头前置科技树: 线性代数空间概念流程简述各空间相关概念详述 空间概念与摄像头 前置科技树: 线性代数 矩阵/向量定…

Gitlab7.14 中文版安装教程

Gitlab7.14 中文版安装教程 注: 本教程由羞涩梦整理同步发布,本人技术分享站点:blog.hukanfa.com转发本文请备注原文链接,本文内容整理日期:2024-01-28csdn 博客名称:五维空间-影子,欢迎关注 …