TCP与UDP笔记汇总
总览
UDP、TCP报文段、TCP可靠传输、TCP三握四挥、TCP重传、TCP流量控制、TCP拥塞控制
传输层有两个协议 TCP和UDP
# UDP是什么
UDP 面向无连接,它可以随时发送数据,支持一对一、一对多、多对多的交互通信
UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序
TCP 有可变长的「选项」字段,而 UDP 头部长度则是不会变化的,无需多一个字段去记录 UDP 的首部长度
其中17是UDP协议的代号
# QUIC
是基于 UDP 协议实现的可靠传输协议的成熟方案,已经应用在了 HTTP/3
QUIC数据包格式
- Header是明文的,包含4个字段:Flags、Connection ID、QUIC Version、Packet Number
- Data 是加密的,可以包含 1 个或多个 frame,每个 frame 又分为 type 和 payload, 其中 payload 就是应用数据
Packet Header 细分这两种:
- Long Packet Header 用于首次建立连接。 源连接ID、目标连接ID
- Short Packet Header 用于日常传输数据。 编号、负载数据、目标连接ID
Short Packet Header 中的 Packet Number
编号 是每个报文独一无二的编号,它是严格递增的,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值。
这样设计的好处:解决了当 TCP 发生超时重传后,客户端发起重传,然后接收到了服务端确认 ACK 。由于客户端原始报文和重传报文序列号都是一样的,那么服务端针对这两个报文回复的都是相同的 ACK。这样的话,客户端就无法判断出是「原始报文的响应」还是「重传报文的响应」,这样在计算 RTT(往返时间) 时应该选择从发送原始报文开始计算,还是重传原始报文开始计算
还有一个好处,QUIC 使用的 Packet Number 单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动
所以,Packet Number 编号单调递增的两个好处:
可以更加精确计算 RTT,没有 TCP 重传的歧义性问题;
可以支持乱序确认,因为丢包重传将当前窗口阻塞在原地,而 TCP 必须是顺序确认的,丢包时会导致窗口不滑动;
# TCP是什么
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它会保证数据不丢包、不乱序。因为IP
层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。所以需要TCP协议
面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的
字节流,即协议的内容是像流水一样的字节流,内容与内容之间没有明确的分界标志,需要我们人为地去给这些协议划分边界,并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理
TCP面向字节流指的是对于应用程序,使用TCP,数据是以字节为单位收发的,比如1K数据,不管你分几次发,对于TCP协议,它们是1K连续的数据。对面也是1K连续的数据。这里没有报文这个概念。比如你是分两次发送的,每次500字节。而对面可能一次就收到的了,也可能要收三次才收到。TCP只保证了1K数据的连续与完整
TCP用序列号和确认应答号(ack)来保证可靠传输。在TCP传送一个数据包时,它会把这个数据包放入重发队列中,同时启动计时器,如果收到了关于这个包的确认信息,便将此数据包从队列中删除,如果在计时器超时的时候仍然没有收到确认信息,则需要重新发送该数据包。另外,TCP通过数据分段中的序列号来 保证所有传输的数据可以按照正常的顺序进行重组,从而保障数据传输的完整
# TCP报文段
序号(seq):在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题
确认号(ack):指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。例如发送确认号为1001,则表示前1000个字节已经被确认接收了。用来解决丢包的问题
数据偏移: 用于计算首部长度,占四位(最大表示1111=15),数据偏移以32位为长度单位,也就是4个字节,因此TCP首部的最大长度是60个字节。即偏移最大为15*4字节
保留: 占六位
六个控制位
URG:紧急指针有效的标志,置1时表示紧急指针有效
ACK:确认号有效的标志,置1时表示确认号(ack)有效。TCP 规定除了最初建立连接时的SYN包之外该位必须设置为 1 。
PSH:推送标志位,接收方的TCP收到该标志位为1的报文段会尽快上交应用进程,而不必等到接收缓存都填满后再向上交付
RST:连接复位,重新连接,该位为
1
时,表示 TCP 连接中出现异常必须强制断开连接。SYN:同步序号,该位为 1 时,表示希望建立连接,并在其「序号」的字段进行序列号初始值的设定
FIN:终止标志位,结束标志,表示关闭连接,当该字段置1时,表示分组将要关闭连接
窗口: 占16比特,以字节为单位。指出发送本报文段的一方的接收窗。
选项: 存放SACK信息,告诉对方哪些信息已收到
传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。
传输层有两个传输协议分别是 TCP 和 UDP,在内核中是两个完全独立的软件模块,所以TCP 和 UDP 可以同时绑定相同的端口
# 如何确定一个TCP的连接
TCP 四元组可以唯一的确定一个连接,四元组包括如下:
- 源地址
- 源端口
- 目的地址
- 目的端口
TCP 连接是由四元组(源IP地址,源端口,目的IP地址,目的端口)唯一确认的,那么只要四元组中其中一个元素发生了变化,那么就表示不同的 TCP 连接的
源地址和目的地址的字段(32 位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。
源端口和目的端口的字段(16 位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。
服务端通常固定在某个本地端口上监听,等待客户端的连接请求。
有一个 IP 的服务端监听了一个端口,它的 TCP 的最大连接数是多少?
对 IPv4,客户端的 IP 数最多为 2
的 32
次方,客户端的端口数最多为 2
的 16
次方,也就是服务端单机最大 TCP 连接数,约为 2
的 48
次方。
# TCP建立连接的过程(三次握手)
TCP 建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP 报文段,称之为三报文握手
三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息
- 主动发起TCP连接建立称为TCP客户(client)。
- 被动等待TCP连接建立的应用进程称为TCP服务器(server)。
一开始,TCP服务器进程首先创建传输控制块,用来存储TCP连接中的一些重要信息。 例如TCP连接表、指向发送和接收缓存的指针、指向重传队列的指针,当前的发送和接收序号等。之后就准备接受TCP客户进程的连接请求, 此时TCP服务器进程就要进入监听状态等待TCP客户进程的连接请求。TCP客户进程也是首先创建传输控制块
第一次握手:
客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号(ISN),首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
第二次握手:
服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号(ISN)。同时会把客户端的 ISN + 1 作为ack 的值,表示自己已经收到了客户端的 SYN。在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y
第三次握手:
客户端收到 SYN 报文之后,会发送一个 ACK 报文,把服务器的 ISN + 1 作为 ack 的值,表示已经收到了服务端的 SYN 报文,确认报文段ACK=1,确认号ack=y+1,序号seq=x+1,ACK报文段可以携带数据,不携带数据则不消耗序号。服务器收到应答后连接建立成功
# 为什么需要三次握手,两次握手可以吗
防止失效的请求报文段被服务器接收,建立一个无效的连接浪费资源。
已失效的连接请求报文段的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
# SYN泛洪(SYN flood)攻击
SYN攻击利用的是TCP的三次握手机制,大量的握手请求涌向TCP服务端,而它们只发出SYN报文而不以ACK响应结束握手,服务端就要为这每一个请求都维持约一分多钟的连接去等待ACK,也就形成所谓的“半连接”。维护这些半连接是需要消耗很多服务器的网络连接资源的。如果短时间内这些资源几乎都被半连接占满,那么正常的业务请求在这期间就得不到服务,处于等待状态。
更进一步的,如果这些半连接的握手请求是恶意程序发出,并且持续不断,那么就会导致服务端较长时间内丧失服务功能——这就形成了DoS(Denial of Service拒绝服务)攻击。这种攻击方式就称为SYN泛洪(SYN flood)攻击
防范措施
如降低SYN timeout时间,使得主机尽快释放半连接的占用;又比如采用SYN cookie设置,如果短时间内连续收到某个IP的重复SYN请求,则认为受到了该IP的攻击,丢弃来自该IP的后续请求报文
# TCP拆除连接的过程(四次挥手)
第一次挥手:
客户端不再有数据发送给服务器,向服务器发送FIN报文表示想要关闭连接,报文中会指定一个序列号。发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
第二次挥手:
服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了
但是,此时服务器可能还有部分数据没有回传给客户端,服务器还要向客户端发送一部分数据才能关闭连接。所以服务器不会立马同意关闭连接,而是先发送表示确认信息的ACK报文,TCP 的连接是全双工的,所以需要双方分别释放到对方的连接,单独一方的连接释放,只代 表不能再向对方发送数据,连接处于的是半释放的状态,所以服务端仍旧可以发送数据给客户端
第三次挥手:
在服务器端完成向客户端传送最后的数据后,此时不再有数据需要传输了。那么服务器也准备关闭连接,所以向客户端发送表示关闭连接的FIN报文
第四次挥手:
客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,客户端发送ACK后,需要有个TIME-WAIT阶段,等待一段时间后,再真正关闭连接,一般是等待2倍的MSL (Maximum Segment Lifetime,最大分段生存期),服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
第四次挥手后为什么客户端需要等待一段时间
客户端会等待一段时间再关闭的原因,是为了防止发送给服务器的确认报文段丢失或者出错,从而导致服务器 端不能正常关闭(服务器没有收到应答超时重传)
已经建立了连接但是客户端突然出现故障了怎么办
TCP还设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
# TCP 分割数据
MTU
:一个网络包的最大长度,以太网中一般为1500
字节。MSS
:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度。
如果 HTTP 请求消息比较长,超过了 MSS
的长度,这时 TCP 就需要把 HTTP 的数据拆解成一块块的数据发送,而不是一次性发送所有数据。数据会被以 MSS
的长度为单位进行拆分,拆分出来的每一块数据都会被放进单独的网络包中。也就是在每个被拆分的数据加上 TCP 头信息,然后交给 IP 模块来发送数据
# 为什么在传输层开始切割数据而不在网络层统一进行切割
- 可靠传输
- 超时重传压力
# TCP可靠传输
ARQ(Automatic Repeat-reQuest) 自动重传请求
停止等待ARQ协议
连续ARQ协议 + 滑动窗口协议
# TCP重传机制
发出去的请求包在规定时间内没有收到ACK,不管是请求包丢失,ACK包丢失,还是网络延迟都会触发重传机制
超时重传
在请求包发出去的时候,开启一个计时器,当计时器达到时间之后,没有收到ACK,则就进行重发请求的操作,一直重发直到达到重发上限次数或者收到ACK。
RTT(Round-Trip Time 往返时延)数据从网络一端传送到另一端所需的时间,也就是包的往返时间。
超时重传时间是以 RTO(Retransmission Timeout 超时重传时间)表示。
超时重传时间 RTO 的值应该略大于报文往返 RTT 的值。实际上报文往返 RTT 的值是经常变化的,因为我们的网络也是时常变化的。也就因为报文往返 RTT 的值 是经常波动变化的,所以超时重传时间 RTO 的值应该是一个动态变化的值。
如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。
也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。
快速重传
接收端如果没有收到期望的数据,而收到后续乱序的包,也给客户端回复 ACK,只不过是重复的 ACK,回复相同的ACK三次以后触发快速重传
例子:如果发送方发出了1,2,3,4,5份数据,第一份先到送了,于是就ack回2,结果2因为某些原因没收到,3到达了,于是还是ack回2,后面的4和5都到了,但是还是ack回2,因为2还是没有收到,于是发送端收到了三个ack=2的确认,知道了2还没有到,于是就马上重转2。然后,接收端收到了2,此时因为3,4,5都收到了,于是ack回6
快速重传不用考虑超时问题但存在该重传多少个包的问题,上述案例发送端既可以重传2,也可以重传2,3,4,5,因为发送端并不清楚这连续的3个ack(2)是谁传回来的,也许发送端发了20份数据,是#6,#10,#20传来的呢。这样,发送端很有可能要重传从2到20的这堆数据
SACK
SACK(Selective Acknowledgment),在快速重传的基础上,返回最近收到的报文段的序列号范围,这样客户端就知道,哪些数据包已经到达服务器了。
DSACK
Duplicate SACK
DSACK,即重复 SACK,这个机制是在 SACK 的基础上,额外携带信息,告知发送方有哪些数据包自己重复接收了。DSACK 的目的是帮助发送方判断,是否发生了包失序、ACK 丢失、包重复或伪重传。让 TCP 可以更好的做网络流控
# TCP拥塞控制
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏,这种情况就叫做网络拥塞
在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大
当网络发送拥塞时,TCP 会降低发送的数据量。这就是拥塞控制,控制的目的就是避免「发送方」的数据填满整个网络。
MSS 只会出现在首次建立连接时的首部选项中,表示每个段最大的数据部分大小
为了在「发送方」调节所要发送数据的量,定义了一个叫做「拥塞窗口」的概念
拥塞窗口 cwnd是发送方维护的一个 的状态变量,它会根据网络的拥塞程度动态变化的。
其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。
TCP的拥塞控制机制主要是以下四种机制:
- 慢启动(慢开始)
慢启动阈值 ssthresh
(slow start threshold)cwnd达到阈值后以线性速度增长。
- 当
cwnd
<ssthresh
时,使用慢启动算法。 - 当
cnwd = ssthresh
时,既可使用慢开始算法,也可以使用拥塞避免算法 - 当
cwnd
>ssthresh
时,使用拥塞避免算法。
- 拥塞避免
拥塞避免未必能够完全避免拥塞,是说在拥塞避免阶段将拥塞窗口控制为按线性增长,使网络不容易出现阻塞
- 快速重传
采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失。而不是等超时重传计时器超时再重传。
快速重传
cwnd = cwnd/2
,也就是设置为原来的一半ssthresh = cwnd
;
超时重传
ssthresh
设为cwnd/2
cwnd
重置为1
- 快速恢复
进入快速恢复之前,cwnd
和 ssthresh
已被更新了:
cwnd = cwnd/2
,也就是设置为原来的一半;ssthresh = cwnd
;
然后,进入快速恢复算法如下:
- 拥塞窗口
cwnd = ssthresh + 3
( 3 的意思是确认有 3 个数据包被收到了) - 重传丢失的数据包
- 如果再收到重复的 ACK,那么 cwnd 增加 1
- 如果收到新数据的 ACK 后,设置 cwnd 为 ssthresh,接着就进入了拥塞避免算法
# TCP流量控制
是点对点的通信控制
TCP 要做流量控制,通信双方各声明一个窗口(缓存大小),标识自己当前能够的处理能力,别发送的太快,也别发的太慢。
如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。
流量控制(flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收。
利用滑动窗口机制可以在TCP连接上实现对发送方的流量控制。
滑动窗口的定义:TCP是双工的协议,会话的双方都可以同时接收和发送数据。窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。在TCP的首部有window窗口字段,也就是窗口大小。这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。发送方的发送窗口不可以大于接收方发回的窗口大小
TCP会话的双方都各自维护一个发送窗口和一个接收窗口。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。
如果发送方操作的速度快于接收方,接收到的数据最终将充满接收方的缓冲区,导致接收方通告一个零窗口 。发送方收到一个零窗口通告时,必须停止发送,直到接收方重新通告一个正的窗口。但是这个报文在中途丢失的,那么发送方的发送窗口就一直为零导致死锁。
解决这个问题,TCP为每一个连接设置一个持续计时器(persistence timer)。只要TCP的一方收到对方的零窗口通知,就启动该计时器,周期性的发送一个零窗口探测报文段。对方就在确认这个报文的时候给出现在的窗口大小(注意:TCP规定,即使设置为零窗口,也必须接收以下几种报文段:零窗口探测报文段、确认报文段和携带紧急数据的报文段)。
糊涂窗口综合症:
当接收方的缓存已满的时候,交互应用程序一次只从缓存中读取一个字节(这时候缓存中腾出一个字节),然后向发送方发送确认信息,此时发送方再发送一个字节(收到的窗口大小为1),这样网络的效率很低。
要解决这个问题,可以让接收方等待一段时间,使得接收缓存已有最够的空间容纳一个最长报文段,或者等到接收缓存已有一半的空间。只要这两种情况出现一种,就发送确认报文,同时发送方可以把数据积累成大的报文段发送。
# TCP粘包
TCP 连接会启⽤延迟传送算法 (Nagle 算法), 在数据发送之前缓存他们. 如果短时间有多个数据发送, 会缓冲到⼀起作⼀次发送
TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包不知道用户边界,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾
产生原因
发送方原因:TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:
- 只有上一个分组得到确认,才会发送下一个分组
- 收集多个小分组,在一个确认到来时一起发送
接收方原因:TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。
如何处理粘包现象?
注明消息头,消息体的长度单位,使用特殊分隔符
发送方:对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。
接收方:接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。
应用层:应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。
解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?
- 格式化数据:每条数据有固定的格式(开始符,结束符),这种方法简单易行,但是选择开始符和结束符时一定要确保每条数据的内部不包含开始符和结束符。
- 发送长度:发送每条数据时,将数据的长度一并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。
UDP会不会产生粘包问题呢?
因为TCP是基于数据流的协议,而UDP是基于数据报的协议
TCP为了保证可靠传输并减少额外的开销(每次发包都要验证),采用了基于流的传输,基于流的传输不认为消息是一条一条的,是无保护消息边界的(保护消息边界:指传输协议把数据当做一条独立的消息在网上传输,接收端一次只能接受一条独立的消息)。
UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。
举个例子:有三个数据包,大小分别为2k、4k、6k,如果采用UDP发送的话,不管接受方的接收缓存有多大,我们必须要进行至少三次以上的发送才能把数据包发送完,但是使用TCP协议发送的话,我们只需要接受方的接收缓存有12k的大小,就可以一次把这3个数据包全部发送完毕。
# TCP队头阻塞
发生在一个TCP分节丢失,导致其后续分节不按序到达接收端的时候。该后续分节将被接收端一直保持直到丢失的第一个分节被发送端重传并到达接收端为止。该后续分节的延迟递送确保接收应用进程能够按照发送端的发送顺序接收数据
# 参考
《图解TCP/IP》
小林coding (xiaolincoding.com) (opens new window)
计算机网络微课堂(湖科大教书匠)
关于TCP传输协议看这一篇就够了 - 知乎 (zhihu.com) (opens new window)
(54条消息) TCP协议详解_独行的喵的博客-CSDN博客_tcp协议 (opens new window)
深入浅出TCP三次握手 (多图详解) - 知乎 (zhihu.com) (opens new window)
(54条消息) TCP三次握手详解_oOoOoOooOO的博客-CSDN博客_tcp三次握手详解 (opens new window)
(54条消息) TCP四次挥手详解_oOoOoOooOO的博客-CSDN博客_tcp四次挥手 (opens new window)
TCP重传机制 - -零 - 博客园 (cnblogs.com) (opens new window)
(37条消息) TCP的拥塞控制(详解)_一颗程序媛0915的博客-CSDN博客_tcp拥塞控制 (opens new window)
(37条消息) TCP 可靠传输机制详解_mocas_wang的博客-CSDN博客_在tcp协议中哪些机制会影响其传输时延, (opens new window)
TCP窗口机制与流量控制 - -零 - 博客园 (cnblogs.com) (opens new window)
(37条消息) 什么是TCP粘包?怎么解决这个问题_渔溪大王的博客-CSDN博客_tcp粘包 (opens new window)