哈工大计算机网络传输层协议详解之:TCP协议

哈工大计算机网络传输层协议详解之:TCP协议

TCP概述

  • 点对点通信
    • 一个发送方、一个接收方
  • 可靠的、按序的字节流
  • 流水线机制
    • TCP拥塞控制和流量控制机制
    • 设置窗口尺寸(基于拥塞控制、流量控制动态的调整窗口尺寸)
    • 介于GBN和SR之间的机制
  • 发送方/接收方缓存
  • 全双工(full-duplex)
    • 同一连接中能够传输双向数据流
  • 面向连接
    • 通信双发在发送数据之前必须建立连接。
    • 连接状态只在连接的两端中维护,在沿途节点中并不维护状态。
    • TCP连接包括:两台主机上的缓存、连接状态变量、socket等。
  • 拥塞控制、流量控制机制

在这里插入图片描述

TCP段结构

在这里插入图片描述

在传输层处理的是一个个的TCP段Segment。

TCP段里的序列号和ACK号不是段的编号,而是利用数据的字节数来计数得到的。

  • U: urgent data,表示紧急数据
  • A: 表示一个标志位,来指示ACK number的字段是否为一个有效的ACK。
  • P: Push data now,标识把数据立即向上层传递
  • RST、SYN、FIN: 连接的建立、销毁等等状态的标志。
  • Receive window: 接收方窗口的大小,标识还能接收的字节的数目,可以用来做流量控制。
  • checksum: 校验和

序列号和ACK

序列号:

  • 序列号指的是段segment中第一个字节的编号,而不是segment的编号
    • 比如,有一个1KB的数据拆成两段,第二个段的序列号不是1(假设序列号从0开始),而是500(从字节0开始编号,500是第二个段的字节起始位)。也就是说,这个序列号是每个段第一个起始字节位的编号,而不是个数的编号。
    • 为什么要这么选?
  • 建立TCP连接时,双方随即选择开始的序列号,并在连接过程中,相互交彼此的信息。

ACKs

  • 表示希望接收到的下一个字节的序列号
  • 累计确认:该序列号之前的所有字节均已被正确接收到

Q:接收方如何处理乱序到达的Segment?

  • TCP规范中没有规定,由TCP的实现者做出决策。
  • 比如在GBN协议中,对于乱序到达的Segment会丢弃,而在SR协议中,乱序到达的Segment会被缓存起来。

这里给出一个telnet远程登陆的应用例子:

在这里插入图片描述

上图中,在发送数据前,主机A和B已经建立连接并交换过信息,因此,这里初始的Seq=42和Ack=79都是之前建立连接时随机选取的初始序号。

  • 在主机A向主机B发送数据C时,该Segment的初始序列号为42,期望收到的下个ACK的序号为79。
  • 主机B接收到数据C后,会返回ACK确认,此时的Segment段的序列号为79,对应于上一个Segment的期望ACK。而段的ACK值为43,是因为本次发送的数据C是一个字符,只有一个字节,因此接收方期望的下一个段的开始字节应该是43。
  • 主机A收到ACK后,还要再发一个ACK确认,此时不携带任何数据。序列号是43,对应于上一个ACK=43。ACK=80,对应于上一个Seq=79,表示发送方期望的下一个序列号是80开始。

TCP可靠数据传输

  • TCP在IP层提供的不可靠服务基础上实现可靠数据传输服务
  • 流水线机制,以便提高性能
  • 累计确认
  • TCP使用单一重传定时器
  • 触发重传的事件包括
    • 超时
    • 收到重复ACK

RTT和超时

问题:如何设置定时器的超时时间?

  1. 大于RTT:但是RTT并不是一个常量,RTT是变化的,根据网络传输情况而变化,同时RTT本身的测量也是个问题。
  2. 过短:导致不必要的重传
  3. 多长:对段丢失反应慢

问题:如何估计RTT的时间

  1. SampleRTT:测量从段发出去到收到ACK的时间(需要忽略重传)
  2. SampleRTT变化:测量多个SampleRTT,求平均值,形成RTT的估计值EstimatedRTT。

在这里插入图片描述

采用指数加权移动平均的方法,使用新的SampleRTT来更新当前的估计值,即考虑了历史结果,也考虑了最新的测量数值。

确认了RTT的估计值后,需要依据RTT来设置对应的定时器

定时器超时时间的设置:

  • EstimatedRTT+“安全边界“。
  • EstimatedRTT变化大—>较大的边界。

因为实际需要设置的超时时间是要比EsitimatedRTT大,因此还需要加上一个边界,这个边界值的设置需要与网络当前的状况相关联。如果网络传输状态较好,则可以设置一个较小的边界,否则需要设置一个较大的边界。

测量RTT的变化值:SampleRTT与EstimatedRTT的差值

在这里插入图片描述

类似于做方差,得到的差值DevRTT一定程度上表示网络的拥塞状况。

因此,有了上述值后,定时器超时时间的设置就可以如下所示:
在这里插入图片描述

思考:为什么是4倍的DevRTT?这样的设置是否合理?

TCP发送方事件

从应用层接收数据

  1. 创建Segment
  2. 序列号是Segment第一个字节的编号
  3. 开启计时器
  4. 设置超时时间TimeOutInterval

超时

  1. 重传引起超时的Segment(只会重传引起超时的那一个Segment)
  2. 重启定时器

收到ACK

  1. 如果确认是此前未确认的Segment
    • 更新SendBase
    • 如果窗口中还有未被确认的分组,重新启动定时器

TCP发送端程序伪代码

TCP发送端程序伪代码如下所示:

在这里插入图片描述

首先初始化一个SendBase和NextSeqNum变量,用于标识发送端滑动窗口的相关参数。接下来是一个无限循环的过程,用switch方法区分不同的event事件。

  • 如果event事件是接收从上层应用层传递的数据,则创建该数据对应的TCP Segment段,其中Seq序列号即为最初初始化的NextSeqNum。如果不存在定时器,则启动定时器。将段传递到IP层。下一个NextSeqNum = NextSeqNum+该段传输数据的字节大小。
  • 如果发生的是timeout事件:重传具有最小序列号的,并且还没有被确认过的的段Segment。并重启启动定时器
  • 如果发生的是ACK确认:如果ACK确认的序列号是大于SendBase的,意味着有新的数据被确认了,由于TCP采用的是累计确认的机制,接收到ACK序列号y表示序列号y之前的Segment都被确认了。因此,更新SendBase = y。如果还有未被确认的Segment,则重启启动定时器。

TCP重传示例

在这里插入图片描述

左图表示了一个ACK丢失的场景。主机A向主机B发送一个8字节大小的数据,序列号为92。主机B向主机A返回一个ACK=100,因为上一个请求的序列号为92,而发送数据大小为为8字节,因此接收方期望的发送方下一个Segment的Seq应该为100。

但是这个返回的ACK丢失了,主机A发送timeout时间,因此又重传了刚刚的8字节数据。

第二次发送方收到了这个ACK=100,因此将SendBase更新为100。下一次再发送Segment则使用100这个序号。‘

右图表示了timeout时间设置过短的场景。主机A基于流水线机制,连续发送了两个Segment,一个为8字节,一个为20字节。主机B两个Segment都收到了,分别返回ACK=100,ACK=120。但是发送端的超时时间设置多短,导致还未收到ACK=100时,直接重传了第一个Seq=92的数据,然后才陆续收到这两个返回的ACK,并根据ACK序号更新SendBase。而之后,接收方又收到了重传的Seq=92的Segment,由于TCP采用的是累计确认机制,因此即使接收方收到Seq=92,仍然返回的ACK=120。因此在累计确认机制下,每个ACK的的确认序号都表示当前序号前的Segment已经被确认了。

再来看下另一个例子

在这里插入图片描述

这次主机A在发送Seq=92和Seq=100的两个序号后,第一个ACK=100的确认丢失了,但是第二个ACK=120的确认正确到达了发送方。还是由于采用的是累计确认机制,发送端在ACK=120后,有理由相信序号120前的Segment都已经被接收方正确接收了,因此直接更新SendBase = 120,而不关心ACK=100丢失的问题。

TCP接收方 ACK生成

TCP接收方,重点是ACK的生成原理和对于场景

在这里插入图片描述

左边表示接收方的事件,右边表示该事件触发的接收方操作。

  • 在接收方到了一个按需到达的Segment,序列号为seq的事件。此时接收方会稍微延迟发送ACK,因为是累计确认机制,会延迟等待(最多500ms)看是否还有下一个Segment到达,如果没有,则发送这个Segment的ACK。
  • 如果有按序到达的Segment,并且前面还有一个Segment在等待发送ACK确认(也就是上一个场景下的等待500ms时有另一个段到达)。此时,接收方触发的操作是,立即发送这两个段的ACK确认。
  • 如果有一个乱序到的Segment,此时接收方触发的操作是,会立即发送一个重复的ACK,表示期望的下一字节的seq。

TCP快速重传机制

TCP实现中,如果发生超时,超时时间间隔将重新设置,即将超时时间间隔加倍,导致其很大。

  • 重发丢失的分组之前要等待很长时间

因此,需要设置额外的重传机制来应对这种情况

通过重复ACK检测分组丢失

  • Sender会背靠背地发送多个分组
  • 如果某个分组丢失,可能会引发多个重发地ACK

因此TCP采用的是流水线和累计确认机制,通过上面的分析我们已经直到,如果接收方收到了乱序的Segment,发送的ACK仍然是那个期望序列号的ACK,也就是期望按序到达的Segment的序号。因此,在流水线机制下,如果有一个Segment丢失了,那么其他的Segment到达后,接收方发送的ACK序号都是那个丢失Segment的序号。因此如果发送方检测到多个某个序号的ACK,就可能说明这个Segment丢失了。

如果Sender收到对同一数据的3个ACK,则假定该数据的段已经丢失

  • 快速重传:在定时器超时之前即进行重传。

快速重传算法伪代码:

在这里插入图片描述

思考:为什么是3次ACK进行快速重传?

TCP流量控制

接收方为TCP连接分配buffer

在这里插入图片描述

左边是有数据从IP层发送过来,然后将数据放到RcvBuffer缓存里,最后向上交付到应用层。蓝色部分表示目前接收端可以用来接收buffer部分。

此时,如果上层应用处理buffer中数据的速度较慢,而发送方发送的数据速率过快,就会导致接收方没有那么多的缓存大小来接收数据,导致buffer缓存溢出。

因此,流量控制的目的就是让发送方不会传输的太多、太快以至于淹没接收方(buffer溢出)。

本质上,流量控制是一场速度匹配机制。

由上图可知,Buffer中的可用空间(spare room)

= RcvWindow

= RcvBuffer - [LastByteRcvd - LastByteRead]

Receiver通过在Segment的头部字段(TCP段的Receive Window字段)将RcvWindow告诉Sender,Sender限制自己已经发送的但还未收到ACK的数据不超过接收方的空闲RcvWindow尺寸。

假设接收方Buffer已经满了,Receiver告知Sender RcvWindow=0,会出现什么情况?

当RcvWindow=0时,即接收方缓存满了,要求发送方不能发送数据了。但是这种情况下,发送方和接收方就无法交互了,也就是说,当后续接收方即使有了空余的buffer,也无法再发送给接收端告知它继续发送数据了。

因此,对于这种情况,需要一些额外的处理。即使RcvWindow=0,在TCP中,发送端仍然可以发送一个很小的一个段Segment,从而带回来接收端的最新buffer大小,以此来解决上述问题。

TCP连接管理

TCP是一个面向连接的协议,在传输实际数据前,需要首先建立连接。除了建立连接外,TCP还需要初始化TCP变量,比如SeqNumber、Buffer和流量控制信息等。数据传输完后,还需要处理连接的拆除。

TCP在建立连接的过程中,采用的是三次握手的机制。

在这里插入图片描述

  1. 客户端向服务端发送一个TCP段Segment,该Segment的标志位为SYN,SYN=1,表示该段为SYN报文段,是不携带任何数据的。同时还需要生成一个初始的序列号(一般随机生成,或者使用定义的机制)。
  2. 服务器收到了SYN报文段后,会返回SYNACK报文段。此时,服务器会为这个连接建议缓存和分配对应的资源,比如Socket。也会初始化服务端的序列号告知客户端。
  3. 客户端收到服务端的SYNACK报文段后,会再答复一个ACK报文段,此时段中的SYN标志位就不再置1了。在这个报文段中,是可以包含数据的。

思考,为什么建立连接是3次握手?2次行不行?经典的TCP建立连接问题

TCP连接建立示意图如下所示:

在这里插入图片描述

TCP连接管理:关闭

TCP连接的关闭,从服务端或客户端发起都可以,一般主要从客户端发起。

  1. 客户端向服务端发送TCP FIN控制报文段segment(也是利用了TCP报文段中的标志位FIN)。
  2. 服务器收到FIN报文段后,回复ACK,关闭连接,发送FIN。
  3. 客户端收到FIN后,回复ACK。进入“等待”状态,确保服务器端能够正确的关闭并且释放资源。在等待的过程中,如果重复收到FIN报文段,会重新发送ACK。
  4. 当服务端收到ACK,连接关闭。

在这里插入图片描述

TCP客户端生命周期

在这里插入图片描述

TCP服务端生命周期

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JermeryBesian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值