网络协议---TCP---TCP中的各种机制

本文详细探讨了TCP协议的各种机制,包括连接管理(三次握手、四次挥手)、确认应答、超时重传、滑动窗口、流量控制、拥塞控制等。重点阐述了拥塞控制的慢开始、快重传与快恢复算法,以及TCP如何通过延迟应答和捎带应答提高效率。此外,还提到了TCP的保活机制和应对异常情况的策略,确保了TCP的可靠性。
摘要由CSDN通过智能技术生成

0、连接管理机制(三次握手四次挥手)

1、确认应答机制(并附带确认序列号)

主机A								主机B
	→→→→→数据(1-1000)		→→→→→
	→→→→→应答(下一个是ack=1001)→→→→→
	→→→→→数据(1001-2000)	→→→→→
	→→→→→应答(下一个是ack=2001)→→→→→
	→→→→→数据(2001-3000)	→→→→→
	→→→→→应答(下一个是ack=3001)→→→→→	

在这里插入图片描述

TCP将每个字节的数据都进行了编号,即为序列号。(TCP包的序列号为该包数据首个字节的序列号)
每一个ACK都会附带确认序列号
   1、=已接收的最后一个字节数据的序列号+1
   2、=接下来要接收字节数据的序列号 = 接下来要接收的TCP数据包的序列号
   3、该序列号前的数据全部已接收
      假设:收到了1-1000和2001-3000,但是没有收到1001-2000
      则ACK包的确认序列号为1001

2、超时重传(计时器太慢而被快重传取代)

在这里插入图片描述
在这里插入图片描述

1、重发的条件:发送者A在特定时间间隔内无法收到接收者B的ACK👈数据包/ACK包 传输过慢or丢包
2、B接收到重复数据,利用序列号丢弃重复数据
3、重传计时器的时间设定:
  ①因网络环境不同而存在差异
  ②设定过长会影响效率;设定过短会频繁发送重复数据
  ③动态计算:Linux中,超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。若重发一次之后仍得不到应答,等待2500ms后再进行重传;如果仍得不到应答,等待4500ms进行重传,依次类推,以指数形式递增。累计到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。

3、滑动窗口(批量传输数据)

引入之前:数据—ACK—数据—ACK…(必须在ACK后才发送下一个数据包)
总的传输时间=N份数据传输时间+N份应答传输时间
时间效益差,尤其在数据往返时间较长的情况下

引入之前之后:改为一次发送多条数据(本质:将多个段的等待时间重叠在一起了。)
总的传输时间=N份数据传输时间重叠成了1份时间,N份应答传输时间,重叠成了一份时间
在这里插入图片描述

发送窗口大小指的是无需等待ACK而可以继续发送的数据的最大值
  1、发送窗口大小由接收方的接收缓冲区大小决定,
   可以在建立TCP连接时协商
  2、窗口越大,则网络的吞吐率就越高。
滑动:窗口范围就是表示当前哪些数据在等待ACK,随着一个ACK到达就立刻发送下一个数据,等待的数据包的范围就在逐渐滑动

操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据才能从缓冲区删掉。

在这里插入图片描述

滑动窗口下的丢包情况

1、ACK丢失or后面的ACK先到
在这里插入图片描述
2、数据丢包or接收方接收顺序反了
如果一直发送不出去,就会超时连接,重置连接。
如果数据包丢了就会进行重传,此处重传只是重传丢了的数据,其他数据不需要额外重传这种叫做"快速重传" (搭配滑动窗口下的超时重传)
在这里插入图片描述
3、如果中间两次丢包

滑动窗口是发送方的概念,接受缓冲区就是一一个固定大小的内存空间(空间大小是固定,可以通过内核的参数配置)如果接受缓冲区满了就不会继续传输了(流量控制机制)
在这里插入图片描述
4、如果是主机接收顺序反了,后发先至
在这里插入图片描述

丢包时的快重传(高速重发控制)机制:
当某一段报文段丢失以后,发送端会一直收到1001这样的ACK,就像是在提醒发送端“我想要的是1001”一样。
如果发送端主机连续三次收到了同样一个“1001”这样的应答,就会将对应的数据1001~2000重新发送。
这时接收端收到了1001以后,再次返回的ACK就是7001了。因为2001~7000接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中。

3、流量控制(通过接收窗口控制发送端发送数据的速率,以便使接收端来得及接受,点对点通信控制)

流量控制本质上,是根据接收方的处理能力来制约发送方的发送速率,根据接受缓冲区的剩余空间大小,来制约发送方的滑动窗口大小,通过TCP报头中的"窗口大小字段"来反映给发送方的。流量控制会影响到发送方的窗口大小,但是不是决定因素

可以通过生产者消费者模型理解,发送方是生产者,接收方的应用程序是消费者.
滑动窗口大小就和消费者应用程序的消费速度也是有关系的,如果剩余空间大,说明消费速度就挺快的,发送速率就可以高一些,反之就发送速率低一些就行了.
如果窗口大小为0,发送方会暂停发送,但是会定时发送一个探测报文. 如果发送方有空间了,就会立刻继续传输.

原因:

接收端处理数据的速度是有限的,若发送速度太快,导致接收端的缓冲区被打满,这时如果发送端继续发送,就会造成丢包问题,继而导致丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。

接收端将自己可以接收的缓冲区大小rwnd放入TCP首部中的“16bit窗口大小”字段,通过ACK端通知发送端。
  窗口大小字段rwnd越大,说明网络的吞吐量就越高。

接收端的ACK包中的rwnd的值取自自身缓冲区可用字节大小
  当缓冲区可用字节变少时rwnd减少;当缓冲区满时rwnd=0,即通知发送方不要再发送数据(此时接收方启用持续计时器,时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。)

在这里插入图片描述
接收端通过TCP首部中的16位窗口字段(接收方剩余可用缓冲区可容纳的字节数rwnd)将窗口大小告诉发送端。注:16位最大只能表示65535,而实际上,TCP首部40字节选项中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位。

在这里插入图片描述
rwnd即接收窗口

4、拥塞控制(防止过多的数据注入到网络中,避免超过网络负荷,全局性问题,实现复杂,只能反复试探)

在这里插入图片描述

拥塞控制设计

拥塞控制是很难设计的,因为它是一个动态的问题,许多情况下,甚至正是拥塞控制机制本身成为引起网络性能恶化甚至死锁的原因。从控制理论的角度来看拥塞控制这个问题,可以分为开环控制和闭环控制两种方法。开环控制就是在设计网络时事先将有关拥塞发生的所有因素考虑周到,一旦系统运行起来就不能在中途改正。
  闭环控制是基于反馈环路的概念,包括如下措施:
  1)监测网路系统以便检测拥塞在何时、何地发生
  2)把拥塞发生的信息传送到可采取行动的地方
  3)调整网络系统的行动以解决出现的问题。

发送方维持一个变量:拥塞窗口cwnd(congestion window),其大小取决于网络的拥塞程度,并且动态变化。
发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就增大一些,以便把更多的分组发送出去。但是只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络的分组数。

发送窗口的上限=min[拥塞窗口cwnd,接收窗口rwnd]

拥塞控制方法

因特网建议标准RFC2581定义了进行拥塞控制的四种算法,即慢开始(Slow-start)、拥塞避免(Congestion Avoidance)、快重传(Fast Restrangsmit)和快回复(Fast Recovery)。我们假定
1)数据是单方向传送,而另外一个方向只传送确认
2)接收方总是有足够大的缓存空间,因为发送窗口的大小由网络的拥塞程度来决定。

慢开始(初始1,每次cwndx2)—ssthresh—拥塞避免(每次cwnd+1)

一开始不能大量发送(最初网络可能拥堵,不能应对大数据量传输),而是逐步增加每次发送的数据量
当新建连接时,cwnd初始化为1个最大报文段(MSS)大小,发送端开始按照拥塞窗口大小发送数据,每当有一个报文段被确认,cwnd就按照1 2 4 8成指数增长
在这里插入图片描述

为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh状态变量。ssthresh的用法如下:
  【每经过一个往返时间RTT】
  当cwnd<ssthresh时,使用慢开始算法。(指数增长,每次x2)
  //当cwnd=ssthresh时,慢开始与拥塞避免算法任意。
  当cwnd>ssthresh时,改用拥塞避免算法。(线性增长,每次+1)

无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限ssthresh设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。在这里插入图片描述

乘法减小:只要出现网络拥塞超时,就把慢开始门限ssthresh减半,并,执行慢开始算法。
        当网络出现频繁拥塞时,ssthresh值就下降的很快,以大大将小注入到网络中的分组数。
加法增大:执行拥塞避免算法执行过程中,拥塞窗口缓慢增大(每次+1),以防止网络过早出现拥塞。

快重传和快恢复(翻阅TCPIP详解卷一二三,貌似快恢复是绑定快重传情况下使用)

1、原本的重传机制:一直等到重传计时器超时才重新发送(不足:等待过久,空闲时间较长)
2、快重传:
  发送方只要连续收到三个重复确认就立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期
  //接收方的ACK包中的确认序号会标识出缺少的数据序号
  在这里插入图片描述
触发快重传机制时的快恢复算法:
  1、当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半,并执行快重传+拥塞避免算法
  2、考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh减半后的大小,然后执行拥塞避免算法。如下图:

相较于原本拥塞后的慢开始(cwnd=1),快恢复则是cwnd=新的ssthresh后紧跟拥塞避免(加法增大)
慢开始算法只是在TCP连接建立时和网络出现超时时才使用。在这里插入图片描述

随机早期检测RED

以上的拥塞避免算法并没有和网络层联系起来,实际上网络层的策略对拥塞避免算法影响最大的就是路由器的丢弃策略。在简单的情况下路由器通常按照先进先出的策略处理到来的分组。当路由器的缓存装不下分组的时候就丢弃到来的分组,这叫做尾部丢弃策略。这样就会导致分组丢失,发送方认为网络产生拥塞。更为严重的是网络中存在很多的TCP连接,这些连接中的报文段通常是复用路由路径。若发生路由器的尾部丢弃,可能影响到很多条TCP连接,结果就是这许多的TCP连接在同一时间进入慢开始状态。这在术语中称为全局同步。全局同步会使得网络的通信量突然下降很多,而在网络恢复正常之后,其通信量又突然增大很多。

为避免发生网路中的全局同步现象,路由器采用随机早期检测(RED:randomearly detection)。该算法要点如下:

使路由器的队列维持两个参数,即队列长队最小门限min和最大门限max,每当一个分组到达的时候,RED就计算平均队列长度。然后分情况对待到来的分组:

①平均队列长度小于最小门限——把新到达的分组放入队列排队。

②平均队列长度在最小门限与最大门限之间——则按照某一概率将分组丢弃。

③平均队列长度大于最大门限——丢弃新到达的分组。
在这里插入图片描述
RED不是等到已经发生拥塞后才把所有队列尾部的分组全部丢弃,而是在检测到网络拥塞的早期征兆时(即路由器的平均队列长度超过一定门限值时),以概率p随机丢弃分组,让拥塞控制只在个别的TCP连接上执行,因而避免全局性的拥塞控制。

RED的关键就是选择三个参数最小门限、最大门限、丢弃概率和计算平均队列长度。最小门线必须足够大,以保证路由器的输出链路有较高的利用率。而最大门限和最小门限只差也应该足够大,是的在一个TCP往返时间RTT中队列的正常增长仍在最大门限之内。经验证明:使最大门限等于最小门限的二倍是合适的。
在这里插入图片描述
 平均队列长度采用加权平均的方法计算平均队列长度,这和往返时间(RTT)的计算策略是一样的。
 在这里插入图片描述

5、延迟应答(为了提高效率,在流量控制的基础上,尽量返回一个合理但是又比较大的窗口)

在这里插入图片描述
延时应答其实就是让ACK的发送时间晚一会(不影响可靠性的前提下)延时的时间中就会给应用程序提供更多的消费数据的机会,此时时间到了,再发ACK的时候,得到的窗口大小(接受缓冲区的剩余空间就会更大)

所有的包都可以延迟应答吗?
不是,
数量限制,每隔N个包就会应答一次
时间限制,超过最大延迟时间就应答一次
具体的数量和超时时间, 依操作系统不同也有差异; 一般N取2, 超时时间取200ms(这个延时应答的等待时间不能超过超时重传的时间.

如果接收数据的主机立即返回ACK应答,此时返回的窗口可能比较小。假设接收端缓冲区为1M,一次收到了500K的数据,若此时立即应答,则返回的窗口大小为500K。但实际上可能处理端处理的速度非常快,几毫秒内就能将数据从缓冲区消费掉。在这种情况下,接收端处理还远未达到自己的极限,即使窗口大小再大一些,也能处理的过来。如果接收端稍微等一会再应答,比如等待几百毫秒再应答,那么此时返回的窗口大小就是1M。

窗口越大,网络吞吐量就越大,传输速率就越高。我们的目标就是在保证网络不拥塞的情况下尽量提高传输效率。

也不是所有的包都可以延迟应答,这是有数量限制和时间限制的。所谓的数量限制,就是每隔N个包就应答一次;所谓的时间限制,就是超过最大延迟时间就应答一次。而具体的数量和超时时间,依操作系统不同也有差异。一般来说N取2,超时时间取 200ms。
在这里插入图片描述

6、捎带应答(ACK可以合并进数据包)

在延迟应答的基础上,我们发现,在很多情况下,客户端服务器在应用层也是“一发一收”的,这就意味着客户端给服务器说了“hello”,服务器也会给客户端回一个“hello”。那么此时ACK就可以搭顺风车,和服务器回应的“hello“一起回给客户端。
在这里插入图片描述

全双工(同时双向收发)

TCP既有发送缓冲区,又有接收缓冲区

由于缓冲区的存在,TCP程序的读和写不需要一一匹配。例如:在写100个字节的数据时,既可以调用一次write写100个字节,也可以调用100次write,每次写一个字节。同理,read也是如此。

7、nagle算法

8、面向字节流的粘包问题

首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包.
在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 只有一个序号这样的字段.
在这里插入图片描述
站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中.
站在应用层的角度, 看到的只是一串连续的字节数据.
那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分 是一个完整的应用层数据包
所以粘包,粘的是应用层的数据报 就是导致处理数据的时候 容易读取半个应用层数据报的情况

粘包问题出现的原因:

(1)发送端需要等缓冲区满时才发送出去,造成粘包;
(2)接收端不及时的接收缓冲区内的包,造成多个包接收。

避免粘包问题的方法------要明确两个包之间的边界:

(1)对于定长的包,保证每次都按固定大小读取即可;
(2)对于变长的包,可以在包头的位置约定一个包总长度的字段,从而就知道了包的结束位置;
(3)对于变长的包,还可以在包和包之间使用明确的分隔符,这个分隔符是由程序员自己来定的,只要保证分隔符不和正文冲突即可。
在这里插入图片描述

UDP协议没有粘包问题

TCP协议本身不帮你区分应用层数据报. (以字节为单位传输)
UDP协议没这个问题. (以UDP包为单位)
对于UDP,若还没有上层交付数据,UDP的报文长度仍然在
因为站在应用层的角度, 使用UDP的时候, 要么收到完整的UDP报文, 要么不收. 不会出现"半个"的情况

9、保活机制

在一些"异常情况"下,TCP对于连接会有特殊的处理。

进程奔溃

这种情况下 TCP连接会正常进行四次挥手端来连接(主要是进程退出 都会自动关闭相关的文件)

主机关机(按流程)

这个按流程就是用户一步一步合理关机
在关机的时候会强制杀死进程 杀进程的时候会进行四次挥手断开连接

主机断电/断网

接收方断电

当接收方断电 发送方发送消息的时候就会出现没有ACK的情况 =>超时重传 => 重传一定的次数 => 重置连接 => 放弃对方然后断开连接

发送方断电

对于接收方来说本来也不知道发送方啥时候发送消息那接收方会一直等下去吗?
肯定不会 其实在TCP中 互相会时不时给对方发送心跳包(一个毫无意义的数据报 只是证明对方还在线 还活着) 所以一旦一段时间都没有收到对方的心跳包 就可以认为对方已经挂了 就会断开连接

心跳包

在这里插入图片描述

TCP异常情况

进程终止:文件描述符的生命周期随进程,所以进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有什么区别。

机器重启:和进程终止的情况相同。

机器掉电或网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset。即使无写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在,若对方不在,也会将连接释放掉。

另外,应用层的某些协议,也有一些这样的检测机制,例如HTTP长连接中,也会定期检测对方的状态。例如QQ,在QQ掉线之后,也会定期尝试重新连接。

TCP可靠性的保证机制总结

TCP复杂是因为它既要保证可靠性,同时又要尽可能的提高性能。

7种可靠性手段:

(1)校验和;
  TCP检验和的计算与UDP一样,在计算时要加上12byte的伪首部,检验范围包括TCP首部及数据部分,但是UDP的检验和字段为可选的,而TCP中是必须有的。计算方法为:在发送方将整个报文段分为多个16位的段,然后将所有段进行反码相加,将结果存放在检验和字段中,接收方用相同的方法进行计算,如最终结果为检验字段所有位是全1则正确(UDP中为0是正确),否则存在错误。
  
(2)序列号(保证数据的按序到达);
  TCP将每个字节的数据都进行了编号,这就是序列号。
序列号的作用:
a、保证可靠性(当接收到的数据总少了某个序号的数据时,能马上知道)
b、保证数据的按序到达
c、提高效率,可实现多次发送,一次确认
d、去除重复数据
数据传输过程中的确认应答处理、重发控制以及重复控制等功能都可以通过序列号来实现

(3)确认应答;
  TCP通过确认应答机制实现可靠的数据传输。在TCP的首部中有一个标志位——ACK,此标志位表示确认号是否有效。接收方对于按序到达的数据会进行确认,当标志位ACK=1时确认首部的确认字段有效。进行确认时,确认字段值表示这个值之前的数据都已经按序到达了。而发送方如果收到了已发送的数据的确认报文,则继续传输下一部分数据;而如果等待了一定时间还没有收到确认报文就会启动重传机制。
  
(4)超时重传;
  当报文发出后在一定的时间内未收到接收方的确认,发送方就会进行重传(通常是在发出报文段后设定一个闹钟,到点了还没有收到应答则进行重传)
  
(5)连接管理(三次握手和四次挥手)
  
(6)流量控制;

(7)拥塞控制。

提高性能的手段:

(1)滑动窗口;
(2)快速重传;
(3)延迟应答;
(4)捎带应答。

在这里插入图片描述

其他:
定时器:超时重传定时器。保活定时器。TIME_WAIT定时器等。

基于TCP应用层协议

HTTP
HTTPS
SSH
Telnet
FTP
SMTP
当然,也包括自己编写TCP程序时自定义的应用层协议。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值