1.基本概念及报文格式
基本概念:
TCP的中文全称为传输控制协议(Transmission Control Protocol),是一种可靠的,面向连接的,基于字节流的传输层通信协议。
报文格式:

序号 :占32⽐特,取值范围0~2^32-1。当序号增加到最后⼀个时,下⼀个序号⼜回到0。⽤来指出本TCP报 ⽂段数据载荷的第⼀个字节的序号。
确认号:占32⽐特,取值范围0~2^32-1。当确认号增加到最后⼀个时,下⼀个确认号⼜回到0。⽤来指出期望 收到对⽅下⼀个TCP报⽂段的数据载荷的第⼀个字节的序号,同时也是对之前收到的所有数据的确认
确认标志位ACK: 只有当ACK取值为1时,确认号字段才有效。ACK取值为0时,确认号字段⽆效。TCP规定:在TCP 连接建⽴后,所有传送的TCP报⽂段都必须把ACK置1。
2.工作原理
建立连接(三次握手)

上图展示了TCP建立连接的大致过程,因为是进行了三次数据交互才建立的连接,所以被形象的称为三次握手。
**第一次握手:**客户端向服务端发送一个特殊的TCP报文段,就是图中的SYN报文段,当SYN=1表示发起一个连接请求或者继续同步请求,很显然,这里的意思是发起一个连接请求,seq是序列号,client_isn是客户端初始序号,它是由客户随机选择的。SYN报文段被封装在一个IP数据报中,被发送给服务端。
**第二次握手:**一旦含该SYN报文段的IP数据报到达服务器主机(前提是的确到达了,不然就没后面什么事了),服务器就会从该数据报中提取出SYN报文段,为该TCP连接分配TCP缓存和变量,并向客户端发送允许连接的报文段,其中SYN被置为1,这个的意思应该指的就是继续同步请求了,server_isn是服务端初始序列号,ack指的是确认序列号,表示接收方期望收到对方下一个报文段的第一个数据字节的序号,即对已接收数据的确认 ,所以客户端下一次发送的报文段的序号就是client_isn+1.
第三次握手:
当客户端接收到包含上述字段的报文段后,会完成该连接的资源初始化工作(这些资源在第一次发送 SYN 报文段时就已初步分配)。接着,客户端向服务器发送一个报文段,此报文段是建立 TCP 连接的最后一个报文段。它对服务器允许连接的报文段进行了确认,具体而言,客户端把server_isn+1这个值放到 TCP 报文段首部的确认字段中,以此完成确认操作。这时,SYN 标志位被设置为 0,意味着同步过程结束,双方正式进入ESTABLISHED状态,TCP 连接宣告建立。
连接断开(四次挥手)
天下没有不散的宴席,TCP连接也是如此,参与一条TCP连接的两个线程中的任何一个都能终止该连接.

**第一次挥手:**客户端向服务端发送一个TCP报文段来请求关闭,其中标志位FIN=1,表示客户端不再发送数据,但是此时仍然能够接收数据。该报文段的序列号为seq即x,在发送完这个报文段后,客户端处于FIN_WAIT_1状态,等待服务端的确认
**第二次挥手:**当服务端接收到了这段报文后会立即向客户端发送一个ACK确认报文,表示服务端已经收到了它的关闭请求,ack=x+1,表示服务端期望客户端下一次发送的第一个报文的序列号为x+1,服务端发送数据的初始序列号为y,服务端在发送完ACK报文后处于CLOSE_WAIT状态。此时客户端到服务端的连接已经关闭,但服务端到客户端的连接仍然是打开的,服务端可以继续向客户端发送数据,客户端在收到ACK报文后处于FIN_WAIT_2状态
**第三次挥手:**当服务端处理完需要向客户端发送的数据后,服务器也准备关闭连接,就会向客户端发送一个带有 FIN 标志位的 TCP 报文段,表示服务端不再向客户端发送数据,ack仍然为1,这里的seq假设为z,分为两种情况,当服务端在第二次挥手后又向客户端发送了一串数据后,那么z就等于y加上发送的这些数据的字节数,如果没有发送数据,那么z=y+1,服务器发送完FIN后进入LAST_ACK状态,等待客户端的最后一次确认。
第四次挥手:
客户端在收到了服务端发送的FIN后,客户端会发送一个ACK确认报文,ack为x+1,seq为客户端之前在通信中确定的值,客户端发送完ACK报文后进入TIME_WAIT状态,服务器收到ACK后进入CLOSED状态,完全关闭连接,而客户端要在TIME_WAIT状态等待一段时间,通常是 2 倍的最长报文段寿命(2MSL),以确保服务器能收到 ACK,如果在这个时间内没有收到服务器的重传请求,客户端才进入CLOSED状态,彻底关闭连接。
3.可靠传输
我们都知道TCP的传输是可靠的,那么它是如何实现数据的可靠传输呢,下面来一一讲解。
序列号与确认应答
TCP会给每个发送的字节数据分配一个序列号,这里的序列号就是我们上面提到的seq。序列号的作用是为了标识数据的顺序,使得接收方能够按照正确的顺序将数据组装起来.比如发送方发送三个数据包过来,seq分别是1,101,201,那么说明第一个数据包包含字节1到100,第二个包含101到200,以此类推。
接收方在收到数据后,会向发送方发送确认应答消息,就是之前提到的ACK数据包,这个消息中会包含它已经成功接收的数据的序列号,表示接收方期望接收的下一个数据的序列号。例如,接收方成功接收到序列号为1到100的数据后,会发送一个 ACK,其中的确认号为101,表示希望发送方接下来发送序列号为 101 及以后的数据。
重传机制
超时重传:发送方在发送数据后会启动一个定时器。如果在定时器超时之前没有收到接收方的确认应答,就会认为数据传输失败,然后重新发送数据。超时时间一般会根据网络状况动态调整,以适应不同的网络环境。
快速重传:当接收方发现收到的数据序列号不连续,即出现了丢失数据的情况时,它会立即向发送方发送重复的确认应答,告诉发送方丢失的数据段的序列号。当发送方收到一定数量(通常是 3 个)的重复 ACK 时,就会认为相应的数据段丢失了,不等定时器超时就会立即重传该数据段。
选择性确认
在TCP通信过程中,如果发送序列中间某个数据包丢失(⽐如1、2、3、4、5中的3丢失了),TCP 会通过重传最后确认的分组后续的分组(最后确认的是2,会重传3、4、5),这样原先已经正确传输的 分组也可能重复发送(⽐如4、5),降低了TCP性能。
后来就发展出了SACK(Selective acknowledgment,选择性确认)技术 ,告诉发送⽅哪些数据丢失,哪些数据已经提前收到 使TCP只重新发送丢失的包(⽐如3),不⽤发送后续所有的分组(⽐如4、5)
选项字段:TCP 首部中有一个可选字段用于实现选择性确认。当接收方支持 SACK 时,会在 TCP 连接建立时通过 "允许 SACK" 选项来告知发送方。在数据传输过程中,接收方可以在确认报文中使用 SACK 选项来报告已收到的不连续的数据块。
确认信息:SACK 选项中包含了一系列的块边界信息,用于指示接收方已经正确接收的数据段的范围。例如,接收方收到了数据段 1、2、4、5、7、8,就可以通过 SACK 选项告诉发送方数据段 [1, 2]、[4, 5]、[7, 8] 已成功接收,相当于精确地给发送方提供了接收情况的 "地图"。
发送方操作:发送方接收到带有 SACK 信息的确认报文后,就可以根据这些信息准确地知道哪些数据段需要重传,哪些已经被接收方成功接收,从而避免不必要的重传,提高传输效率。
4.流量控制
TCP 的流量控制主要是通过滑动窗口机制来实现的,目的是确保发送方发送数据的速度不会超过接收方处理数据的能力,防止数据丢失和网络拥塞。
4.1滑动窗口原理
将原理前先要了解什么叫做窗口,在 TCP 中,窗口是指在一段特定时间内,发送方或接收方可以处理的数据量范围。对于发送方来说,发送窗口决定了它可以在未收到确认的情况下连续发送的数据量;对于接收方来说,接收窗口表示其接收缓冲区中当前可用的空间大小,即能够接收和处理的数据量。
随着数据的发送和确认,窗口会在数据序列上 "滑动"。发送方每收到一个确认应答,就可以将发送窗口向前滑动,允许发送更多的数据;接收方每处理完一段数据,接收窗口也会相应地向前滑动,为接收新的数据腾出空间。
4.2窗口大小的确定与调整
接收方通告窗口:接收方会在发送给发送方的 TCP 报文段中,通过窗口字段来告诉发送方自己当前的接收窗口大小。这个窗口大小是根据接收方的接收缓冲区剩余空间、处理能力等因素动态计算出来的。例如,接收方的接收缓冲区总大小为 10KB,当前已经占用了 3KB,那么它可能会将接收窗口大小设置为 7KB,并在 ACK 报文中将这个窗口大小值通告给发送方。
发送方窗口调整:发送方根据接收方通告的窗口大小来调整自己的发送窗口。发送方的发送窗口大小不会超过接收方通告的窗口大小,以确保发送的数据不会超出接收方的处理能力。同时,发送方还会考虑网络拥塞等因素,综合确定最终的发送窗口大小。
动态调整:在数据传输过程中,窗口大小会根据网络状况和双方的处理能力不断动态调整。如果接收方处理数据的速度加快,其接收缓冲区的空闲空间增加,就会增大通告给发送方的窗口大小,允许发送方发送更多的数据;反之,如果接收方处理速度变慢或缓冲区快满了,就会减小窗口大小,让发送方减慢发送速度。
4.3流量控制的具体过程
数据发送与窗口滑动:发送方在发送窗口范围内发送数据,并启动定时器。当发送方收到接收方对已发送数据的确认应答时,根据确认应答中的信息,将发送窗口向前滑动。例如,发送方发送了序列号为 101 到 200 的数据,接收方正确接收后发送 ACK 确认,确认号为 201,发送方收到这个 ACK 后,就可以将发送窗口向前滑动,开始发送序列号为 201 及以后的数据。
窗口关闭与打开:当接收方的接收缓冲区已满时,它会将通告给发送方的窗口大小设置为 0,通知发送方暂停发送数据,这就是所谓的 "窗口关闭"。发送方收到窗口大小为 0 的通告后,会停止发送数据,直到接收方再次发送通告,将窗口大小调整为大于 0 的值,即 "窗口打开",发送方才能继续发送数据。
糊涂窗口综合征:在某些情况下,如果接收方每次只腾出少量的接收缓冲区空间,就通告发送方发送少量的数据,可能会导致发送方发送很多小的数据包,降低网络效率,这种情况称为 "糊涂窗口综合征"。为了避免这种情况,TCP 采用了一些策略,如接收方在缓冲区有足够空间时才通告发送方发送数据,发送方在发送数据时尽量将数据积累到一定大小再发送等。

4.4特殊情况
⼀开始,接收⽅给发送⽅发送了0窗⼝的报⽂段,后⾯,接收⽅⼜有了⼀些存储空间,给发送⽅发送 的⾮0窗⼝的报⽂段丢失了,发送⽅的发送窗⼝⼀直为零,双⽅陷⼊僵局。

解决方案
当发送⽅收到0窗⼝通知时,这时发送⽅停⽌发送报⽂ 并且同时开启⼀个定时器,
隔⼀段时间就发个测试报⽂去询问接收⽅最新的窗⼝⼤⼩
如果接收的窗⼝⼤⼩还是为0,则发送⽅再次刷新启动定时器
5.拥塞控制
5.1概念

拥塞:在某段时间,若对⽹络中某⼀资源的需求超过了该资源所能提供的可⽤部分,⽹络性能就要 变坏,这种情况就叫作拥塞(congestion)。
拥塞控制是⼀个全局性的过程
涉及到所有的主机、路由器,以及与降低⽹络传输性能有关的所有因素
是需要靠所有节点共同努⼒的结果
防⽌过多的数据注⼊到⽹络中,使⽹络能够承受现有的⽹络负荷。
相⽐⽽⾔,流量控制是点对点通信的控制
5.2拥塞控制的常⽤算法
⽅法概述
慢开始(slow start,慢启动)、拥塞避免(congestion avoidance)
快速重传(fast retransmit)、快速恢复(fast recovery)
⼏个缩写
cwnd(congestion window):拥塞窗
rwnd(receive window):接收窗
18 swnd(send window):发送窗,swnd = min(cwnd, rwnd)
5.2.1慢开始
●cwnd的初始值⽐较⼩,然后随着数据包被接收⽅确认(收到⼀个ACK)
cwnd成倍增⻓(指数级)

轮次 1:发送方 A 的 cwnd 为 100 字节,即可以发送一个 MSS 大小的数据段 M1。发送后等待接收方 B 的确认,B 收到 M1 后,向 A 发送对 M1 的确认。
轮次 2:因为收到了 M1 的确认,根据慢开始算法,发送方 A 的 cwnd 翻倍,变为 200 字节,也就是可以发送两个 MSS 大小的数据,所以 A 发送数据段 M2 和 M3。接收方 B 收到 M2 和 M3 后,一次性确认 M1 到 M3 这三个数据段。
轮次 3:由于收到了 M1 到 M3 的确认,cwnd 再次翻倍,变为 400 字节,此时 A 可以发送 4 个 MSS 大小的数据,即 M4 到 M7。接收方 B 收到后,确认 M4 到 M7 这四个数据段。
后续:按照慢开始算法,下一轮 cwnd 会变为 800 字节,可发送更多的数据段(如 M8、M9 等)。只要 cwnd 不超过接收方的 rwnd(3000 字节),且不触发拥塞控制的其他机制,发送方就可以持续按照慢开始算法增大 cwnd 来发送数据。
5.2.2拥塞避免

ssthresh(slow start threshold):慢开始阈值,cwnd达到阈值后,以线性⽅式增加
拥塞避免(加法增⼤):拥塞窗⼝缓慢增⼤,以防⽌⽹络过早出现拥塞
乘法减⼩:只要⽹络出现拥塞,把ssthresh减为拥塞峰值的⼀半,同时执⾏慢开始算法(cwnd⼜恢复到初始值) 当⽹络出现频繁拥塞时,ssthresh值就下降的很快
5.2.3快重传
接收⽅
每收到⼀个失序的分组后就⽴即发出重复确认 使发送⽅及时知道有分组没有到达 ⽽不要等待⾃⼰发送数据时才进⾏确认
发送⽅
只要连续收到三个重复确认(总共4个相同的确认),就应当⽴即重传对⽅尚未收到的报⽂段 ⽽不必继续等待重传计时器到期后再重传

对于个别丢失的报⽂段,发送⽅不会出现超时重传,也就不会误认为出现了拥塞⽽错误地把拥塞窗 ⼝cwnd的值减为1。实践证明,使⽤快重传可以使整个⽹络的吞吐量提⾼约20%。
5.2.4快恢复
当发送⽅连续收到三个重复确认,说明⽹络出现拥塞
就执⾏" 乘法减⼩" 算法,把ssthresh减为拥塞峰值的⼀半
与慢开始不同之处是现在不执⾏慢开始算法,即cwnd现在不恢复到初始值
⽽是把cwnd值设置为新的ssthresh值(减⼩后的值) 然后开始执⾏拥塞避免算法(" 加法增⼤"),使拥塞窗⼝缓慢地线性增⼤
