TCP是如何实现可靠传输的?
在计算机网络的经典五层协议中,TCP属于运输层,实现了进程间的通信,保证了数据的可靠传输,属于计算机网络协议族中最重要的协议之一,那么TCP是如何实现可靠数据传输的呢?
底层实现
运输层的进程间通信是通过socket实现的,socket是一个抽象的概念,在Linux系统中以文件的形式存在。网络层通过IP来区分主机,运输层则增加了端口的概念来区分进程。TCP协议中使用目标IP、目标端口、源IP、源端口来定义一个socket,只需要在运输层的报文头部附加上这些信息,目标主机就会知道数据要发送那个socket,对应监听该socket的进程就可以收到数据进行处理。
TCP报文格式
TCP报文包括首部和数据部分,首部附加了TCP报文的信息,首部长度固定部分为20字节,还有40字节的可选部分,具体如下图所示:
其中几个关键字段的作用如下:
- 源端口和目的端口:分别16个字节(表示范围0-65535),用来区分主机上的进程
- 序号:TCP连接中的每个字节都编一个序号,表示本报文的第一个字节在整个数据包中的偏移位置
- 确认号:期望收到对方的下一个报文段的数据的第一个字节的序号
- 数据偏移:首部长度,4字节为单位
- 标志位
- ACK:ACK=1表示接收发向发送方发的确认报文
- SYN:同步SYN=1表示是一个连接请求或连接接受报文
- FIN:FIN=1表示发送方已经发送完毕,可以断开连接
- 窗口:发送方接收缓冲区剩下的字节数
- 校验和:检验报文在网络传输过程中是否发生了变化
- 选项字段:
- 窗口扩大选项,用于流量控制
- 时间戳选项
- 选择确认选项,由于接收方收到了不连续的报文,告知发送方目前收到的数据报范围(两个4字节的边界表示)
可靠传输原理
网络层只管尽可能将数据从一个主机发送到另一个主机,并不保证数据可靠到达,由于网络环境总是不稳定的,可能存在丢包、差错等请求,TCP则通过一系列的机制在运输层保证了数据的可靠传输。
网络传输可能发生的异常情况和解决方法:
- 丢包:超时重传
- 差错:校验码来检验数据正确收到
停止等待协议
要实现可靠传输,最简单的方法就是发送方发送一个报文,接收方收到报文后发送确认报文表示我收到了,你可以发下一个了,传输模型如下:
这种方式保证可靠传输称为停止等待协议,这种方式缺点也很明显,效率非常低。
连续ARQ协议
为了提高传输效率,充分利用带宽,发送方会连续的发送数据包,如下图所示:
客户端不等收到前一个包的确认报文就开始不断的发下一个包,这样可以充分利用网络带宽,提高传输效率,但是于此同时也带来了另外的问题,那么TCP是如何解决这些问题的?
确认报文冗余
累计确认:网络中充斥着大量的发送包和确认回复报文,这些数据只是为了确认报文到达,并不是实际需要传输的数据。是不是一定要每一个报文都要发一个回复确认的报文呢,TCP采用了累计确认的方法:接收方在累计收到了一定量的数据包后发送一个确认报文告诉发送方在此之前的数据包都已经收到了,这样便可以减少确认报文的数量,提高带宽利用率。
丢包的处理
GBN(回退n步):如果发生丢包的情况,在连续ARQ中,如果接受方收到了123 567个字节,编号为4字节的包丢失了,按照累计确认只能发送3的确认回复,567都要丢掉,因为发送发会进行重传。
选择确认ACK:在TCP报文头部的选项字段部分设置已收到的报文,每一段用两个边界来确定,比如上述情况可以用[1,3]和[5,7]来表示,客户端就会根据选项只重传丢失的数据段。
滑动窗口
因为接收方读数据的能力有限,发送发不能一直发送报文直到把缓冲区所有数据发送完,这样会导致接收方无法接收丢弃掉数据包,发送方收不到确认认为超时又会继续重传,产生了大量无用数据的重传。对此情况TCP使用滑动窗口来解决,基本模型如下:
- 发送方根据接受方缓冲区的大小,设置自己可发送窗口大小,处于窗口内的数据表示可以发送,之外的数据不能发送
- 当窗口内的未确认数据收到确认回复时,整个窗口往前移动,知道发送完所有数据
滑动窗口机制实现了TCP的流量控制,不至于发送太快导致太多的数据丢弃和重传。
拥塞控制
为了避免网络过分拥挤导致丢包严重,传输效率低,TCP实现了拥塞控制机制,拥塞控制的解决办法本质上是流量控制,控制发送方发送的速度,而上文提到流量控制是通过滑动窗口来实现的,所以最终也是通过调整发送方的滑动窗口大小来实现的。
拥塞控制的几个重要的概念:慢启动、拥塞避免、快恢复、快重传
Reno算法模型
- 慢启动:最开始的时候把窗口设置为较小的值,然后每轮变成两倍(虽然叫慢启动,但其实是指数增长)
- 拥塞避免:当窗口大小达到初始阈值ssthresh,每轮窗口大小增加1(试探网络最大的负载能力)
- 如果发生了超时,表示极可能发生了拥塞,此时直接执行慢启动,尽可能让网络中的报文先接收,以尽快恢复网络状况。
- 快重传:如果收到三个重复的ACK,表示中间有段数据丢包了,发送方无需等待计时器到达超时时间,立即进行重传丢失的报文段。
- 快恢复:连续收到了三个重复ACK,说明网络情况还不是很拥堵,此时将窗口初始的阈值减半,然后执行拥塞避免,这个过程称为快恢复。
Reno算法是比较常见的TCP实现的拥塞控制算法,其他拥塞算法还有Tahoe(已废弃不用)、New Reno等,通过拥塞控制算法可以很大程度避免网络拥挤。
参考
【书籍】计算机网络:自顶向下方法
【码农有道】这一篇TCP总结请收下