TCP可靠数据传输

267 阅读10分钟

TCP可靠数据传输

网络层服务(IP服务)是不可靠的

TCP的可靠数据传输服务确保一个进程从其接收缓存中读出的数据流是无损坏、无间隙、非冗余和按序的数据流,即该字节流与连接的另一方端系统发出的字节流是完全相同的

序列号与确认应答

确认应答:当发送方将数据发出后会等待接收方的确认应答,如果有确认应答,说明数据已经成功到达接收方,反之,可能是存在丢包,就进行重发,从而实现可靠传输

  • 可能是数据包丢失,重发即可
  • 可能是确认应答丢失,这种情况再次收到数据接收方会放弃,并重发应答

序列号:序列号是按顺序给发送数据的每一个字节都标上号码的编号,接收方查询接收数据TCP首部中的序列号和数据的长度,将自己下一步应该接受的序号作为确认应答送回

综上,通过序列号和确认应答可以实现可靠的数据传输

超时重发

重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔,如果超过这个时间仍未收到应答,就会对数据进行重发

重发后若还是收不到确认应答,则再次发送,且等待确认应答时间会以2倍、4倍的指数函数延长

数据不会无限的重发,到达一定重发次数若还是收不到确认应答,就会判断为异常,强制关闭连接

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

TCP是面向连接的传输,面向连接是指在数据通信开始之前先做好通信两端之间的准备工作

三次握手

  • 通过TCP首部发送一个SYN包作为建立连接的请求等待确认应答
  • 如果服务端发来确认应答ACK和建立连接请求SYN,则认为可以进行数据通信
  • 客户端返回一个确认应答ACK

四次挥手

  • 客户端发送请求断开连接的FIN包
  • 服务端收到后发送确认应答ACK,是针对刚刚的FIN
  • 服务端传送完接下来的数据后,再发送请求断开连接的FIN包
  • 客户端收到后发送确认应答ACK
  • 服务端收到后断开连接
  • 客户端在2个MSL时间后断开

窗口控制

TCP以段为单位发送数据

在介绍窗口之前,先说一下MSS:

发送数据包的单位,也就是最大消息长度(MSS),在传送大量数据时,是以MSS的大小将数据进行分割发送的

MSS的确定是在三次握手的SYN包相互通知对方自己的MSS的,最终是选择较小的MSS发送数据

TCP以一个段为单位发送数据,每发一个段进行一个确认应答的处理(按数据包进行确认应答)

image.png

这样的传输方式有一个缺点:包的往返时间越长,通信性能越低,因此TCP引入了窗口的概念

窗口

确认应答不再是以每个分段,而是以更大的单位进行确认,转发时间将会被大幅度缩短,也就是说发送方发送一段后不必要一直等待确认应答,而是继续发送

image.png

窗口大小就是指无需等待确认应答而可以继续发送数据的最大值,如上图中窗口大小就是4个段

在收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置,这样可以顺序地将多个段同时发送提高通信性能

image.png

重发控制

分为两种情况,一种是确认应答丢失,一种是报文段丢失

确认应答丢失

在没有使用窗口控制的情况下,确认应答丢失也会进行重发数据

而使用了窗口控制即使某些确认应答丢失也不会进行重发,因为可以通过下一个确认应答进行确认

报文段丢失(快速重传)

接收方如果收到一个自己应该接收的序号以外的数据时,会针对当前位置收到数据返回确认应答

这样同一个序号的确认应答会重复不断地被返回,当发送方收到3次同一个确认应答,就会将其所对应的数据进行重发

这种方式比超时重传更加高效,因此也被称为快速重传

image.png

流量控制

接收缓存

一条TCP连接的每一侧主机都为该连接设置了接收缓存

当TCP连接收到正确、按序的字节后,就将该数据放入接收缓存,相关联的应用进程会从该缓存中读取数据

接收缓存溢出

如果某应用程序读取数据相对缓慢,而发送方发送太多太快,就会导致接收缓存溢出

img

接收窗口

TCP通过让发送方维护一个接收窗口来提供流量控制

接收窗口用于给发送方一个指示——接收方还有多少可用的缓存空间

流量控制

其实是一个速度匹配服务,就是让发送方的发送速率和接收方应用程序的读取速率相匹配

实现:接收方告诉发送方接收窗口的大小

img

死锁

当发送方查看到接收窗口 > 0 时会继续发送数据,但是如果接收方发送的报文丢失了,发送方没有成功收到

这样会导致一个僵局:接收方发送了报文,但是发送方由于某些网络原因未收到,而接收方在等待发送方继续发送数据,发送方又在等待接收方的报文

解决方法:

  1. 当发送方收到接收窗口为0的报文后,就停止发送报文

  2. 开启一个定时器,每隔一段时间就发送一个测试报文去询问接收方

    • 如果接收方返回一个接收窗口>0的报文,就代表接收缓存有位置了,发送方可以继续发送数据
    • 如果返回的还是接收窗口=0的报文,发送方继续等待,刷新启动计时器

流量控制的简述

TCP提供一种机制可以让发送端根据接受端的实际接收能力来控制发送的数据量,防止接收缓存的溢出导致丢包,降低网络流量

具体的操作是接收段向发送端通知自己可以接受数据的大小,这样发送端会发送不超过这个限度的数据,这个大小限度就被称为窗口大小

TCP首部有一个字段用来通知窗口大小,接收段将自己的接收缓存大小放入这个字段通知发送端

当窗口更新通知在传送途中丢失,可能会导致无法通信,因此发送方会时不时发送一个叫做窗口探测的数据段,此数据段仅含一个字节以获取最新的窗口大小信息

简单来说,就是发送端会根据接收端的指示,对发送的数据量进行控制

拥塞控制

网络拥塞

到达某一部分网络的分组数量过多网络来不及处理,导致网络性能下降(就像收费站堵车一样)

当网络变得拥塞时由于路由器缓存溢出造成丢包

解决方法:让每一个发送方根据所感知到的网络拥塞成都来限制其能向连接发送流量的速率

如何限制发送流量

拥塞窗口

发送方会维护一个变量:拥塞窗口,通过调节拥塞窗口的值来调整发送方向连接发送数据的速率

如何感知拥塞

其实丢包可以定义为:要么出现超时,要么收到来自接收方的3个冗余ACK

当出现拥塞时,路由器的缓存会溢出,就会导致丢包,因此当出现超时或收到3个冗余ACK的时候,发送方将就认为出现了拥塞的

如何改变发送速率

  • 当出现丢失意味着拥塞,应当降低发送方的速率
  • 一个确认报文意味着一切顺利,网路不拥塞,可以增加拥塞窗口的长度(可以增大发送速率)

下面介绍TCP拥塞控制算法,分为三个部分:慢启动、拥塞避免、快速恢复

慢启动

当到达阀值(ssthresh)之前,拥塞窗口以指数方式增长

拥塞避免

到达阀值后,拥塞窗口以线性方式增长

快速恢复

快速恢复和快速重传算法一般是同时使用的

1.当收到3个重复ACK时,把ssthresh设置为cwnd的一半,把cwnd设置为ssthresh的值加3,然后重传丢失的报文段,加3的原因是因为收到3个重复的ACK,表明有3个“老”的数据包离开了网络。

2.再收到重复的ACK时,拥塞窗口增加1。

3.当收到新的数据包的ACK时,把cwnd设置为第一步中的ssthresh的值。原因是因为该ACK确认了新的数据,说明从重复ACK时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态。

简短来说,就是令 ssthresh = cwnd/2,cwnd = ssthresh,即再次进入拥塞避免状态

拥塞控制简述

有了窗口控制后,虽然可以连续发送大量数据,但是可能会出现网络拥堵,因此引入了拥塞控制,在一开始的时候先通过慢启动算法对发送的数据量进行控制

在慢启动开始时,现将拥塞窗口的大小设置为一个数据段发送数据,每收到一次确认应答,拥塞窗口的值就按指数函数的方式增长,这样可以在减少通信开始时连续发包导致的网络拥塞

但是随之指数增长,为了防止出现网络拥塞,我们引入慢启动阀值的概念,只要拥塞窗口的值大于这个阀值,会进入拥塞避免阶段,是以线性方式增加拥塞窗口的大小

在通信开始时,TCP并没有设置慢启动阀值,而是在出现重复确认应答时,才设置阀值会当时拥塞窗口大小的一半(也就是快速恢复阶段),当出现丢包时,将阀值设置为当前拥塞窗口的一半,并将拥塞窗口设为1,重新进入慢开始阶段