一、TCP如何保证可靠传输
- 确认和重传:接收方收到报文就会确认,发送方发送一段时间后没有收到确认就会重传。
- 序号机制(序号、确认号):确保了数据是按序、完整到达。
- 数据校验:TCP报文头有校验和,用于校验报文是否损坏。
- 数据合理分片和排序:tcp会按最大传输单元(MTU)合理分片,接收方会缓存未按序到达的数据,重新排序后交给应用层。而UDP:IP数据报大于1500字节,大于MTU。这个时候发送方的IP层就需要分片,把数据报分成若干片,是的每一片都小于MTU。而接收方IP层则需要进行数据报的重组。由于UDP的特性,某一片数据丢失时,接收方便无法重组数据报,导致丢弃整个UDP数据报(可以延伸到IP层的路径MTU发现)。
- 流量控制:当接收方来不及处理发送方的数据,能通过滑动窗口,提示发送方降低发送的速率,防止包丢失。
- 拥塞控制:当网络拥塞时,通过拥塞窗口,减少数据的发送,防止包丢失。
二、TCP重传
首先说下常见的四种重传机制
超时重传 快速重传 SACK D-SACK
1、超时重传
在发送数据时,设一个定时器,超过一定时间未收到确认,就重发该数据,这就是超时重传
有两种情况会发生超时重传,分别是发送的数据包的丢失和确认报文丢失
超时重传(RTO)是有讲究的,RTT是报文往返时间,首先RTO毋庸置疑一定要大于RTT,具体这两个是什么关系呢,可以自行搜搜,按照比例来计算。
2、快速重传
超时重传是以时间为标准,而快速重传是以数据为标准。快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。一般来说连续收到三个相同的ACK的时间还是比RTO少的,所以相对超时重传,这完全可以称得上快速重传哈哈。
但是这种快速重传的方式还是有问题的,连续收到三次相同ACK,是重传一个,还是重传所有的问题。
3、SACK(Selective Acknowledgment)
TCP 头部选项字段里加一个 SACK 的东西,它可以将已收到的数据的信息发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
4、Duplicate SACK
主要使用了 SACK 来告诉发送方有哪些数据被重复接收了
三、滑动窗口
1、滑动窗口介绍
TCP为每个数据包都单独设置确认应答的话,包往返时间越长,网络的吞吐量就越小,网路利用率就越低。
为解决这个问题,故TCP引入窗口这个概念。(其实跟http1.1的pipeline技术某种层面上差不多,都是为了提高效率,把一个个单独的确认应答,换成一连串的发送与应答)。
滑动窗口的大小就是就是指无需等待确认应答,而可以继续发送数据的最大值。
通常窗口的大小由接受端确定,每次接收端发送ACK报文,会在TCP报文的窗口字段上填入自己的接收窗口值,然后发送端会取min(拥塞窗口,接收端窗口)作为自己的窗口大小。
2、发送端与接收端的滑动窗口构成
发送端滑动窗口
已发送且被确认部分 | 已发送未被确认部分 | 未发送但可发送部分 | 不可发送部分
其中发送窗 = 已发送未确认部分 + 未发但可发送部分。
//具体深入到Linux,参数意义
SND.WND:表示发送窗口的大小(大小是由接收方指定的);
SND.UNA(Send Unacknoleged):是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节。
SND.NXT:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号。
接受端滑动窗口
已接收 | 未接收但准备接收 | 未接收不准备接收。
接收窗 = 未接收但准备接收部分。
//参数意义
RCV.WND:表示接收窗口的大小,它会通告给发送方。
RCV.NXT:是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号。
发送窗内数据只有当接收到接收端某段发送数据的ACK响应时才移动发送窗,左边缘紧贴刚被确认的数据。接收窗也只有接收到数据且最左侧连续时才移动接收窗口。