tcp
重传机制
方式
超时重传
概念
- 发送数据时设定一个定时器,若在指定时间内没有收到应答报文,就会重发数据
发生超时重传的时机
- 数据包丢失
- 确认应答丢失
超时时间RTO选择
- 略大于RTT
- 重传超时策略:超时时间间隔加倍
快速重传
概念
- 发送方可以一次发送多个数据包,若中间的某个数据包丢失了,接收方会一直回复这个丢失的数据包应答报文,接收方若收到三次这个数据包的应答报文,就知道该报文还没有被接收方收到,可以重传这个数据包
问题
- 因为接收方对后续的数据包也返回了丢失的那个应答报文,所以发送方不知道后续的数据包是否丢失,也就不知道应该重传丢失的数据包还是把后续的数据包都重传
SACK
概念
- 选择性重传,解决快速重传不知道重传哪些报文的缺点
实现方式
- 在tcp头部“选项”字段里加一个SACK,将缓存的地图发送给发送方,这样发送方就知道哪些数据接收方收到了,哪些数据接收方没有收到,以便重传接收方没有收到的数据
参数
- 要开启SACK,需要发送方和接收方都支持:net.ipv4.tcp_sack,linux2.4以后默认打开
D-SACK
概念
- 对SACK的扩展,通过SACK告诉发送方哪些数据被重复接收了
实现方式
- 若有发送方有重复发送数据包,会通过SACK告诉发送方这这个数据包已被发送过
好处
发送方能够知道是发出去的包丢了还是接收方发送的ACK丢了
- SACK若告知这个包已被发送过,那么说明是接收方发送的ACK丢了
发送方可以知道发出去的数据包是否被网络延迟了
- 发送方在延迟之后会重发数据包,之前的数据包若一段时间后到达了接收方,接收方返回的应答报文中能看到该数据包已经被接收了,是个重复的报文,说明被网络延迟了,而重发的数据包已被收到
序列号与确认应答(ACK)保证了tcp的可靠传输
滑动窗口
引入原因
- 每发送一个数据都需要进行确认应答,收到了再发送下一个,效率比较低。在窗口大小限制范围内,可以无需等待上一个数据包应答,就可以继续发送下一个数据包
错误处理
累计应答
发送数据包丢失
- 若发送方发送了一批数据包,中间的某个数据包丢失,那么接收方回复应答时ACK会回复丢失的那个数据包,这样接收方就知道丢失的数据包是哪一个,因此可以重新发送;
应答报文丢失
- 若接收方返回的这一组数据包中,某一个应答报文丢失了,只要最后一个应答报文发送成功了,接收方就知道这个数据包的其实是收到了的
窗口大小
tcp头里的字段window
- 接收方通过这个字段告诉接收方自己还有多少缓冲区可以接收数据,发送方就可以根据接收方的处理来发送数据,以免导致接收方处理不过来,因此窗口的大小是由接收方决定的
接收方和发送方的窗口
- 接收方和发送方的窗口大小基本相等,因为发送方的窗口大小取决于接收方,当接收方处理能力快,窗口变大,通过tcp报文中的window字段告诉接收方,若传输过程中出现了延迟,所以这时两个窗口大小不一致
拥塞控制
概念
- 流量控制是避免发送方填满接收方的缓存,但若因为其他主机之间的通信造成网络拥堵,会有超时和丢包发生,这样会导致重传 ,网络负担会更大,进入恶性循环,所以tcp不能忽略网络上发生的事,当网络发生拥堵时,它会降低数据的发送量。拥塞控制的目的就是避免发送方的数据填满整个网络
拥塞窗口cwnd
发送窗口swnd和接收窗口rwnd是约等于的关系,有了拥塞窗口的概念后,发送窗口swnd=min(cwnd, rwnd)
- 网络中没有出现拥塞,cwnd会增大,反之会减小
判断网络拥塞的方法
- 发生超时重传
相关算法
慢启动
- tcp刚建立连接完成,会有个慢启动的过程,一点一点提高发送数据包的数量
- 每接收到一个ack,cwnd大小就会加1,初始化时,cwnd大小为1,即cwnd大小按指数级增长
ssthreshold,slow start thresold,慢启动门限
- 当cwnd < ssthreshold时,会采用慢启动算法
- 当cwnd >= ssthreshold时,会使用拥塞避免算法
拥塞避免
- 每收到一个ack,cwnd增加1/cwnd。即囤积了cwnd这么多个包后,一次性发送过去。之后都会这样发送,cwnd按线性增长
- 当一直这么增长,会慢慢进入拥塞状况,于是开始出现丢包现象,这时需要对丢失的数据进行重传,当触发了重传机制也就进入了拥塞发生算法
拥塞发生
超时重传
- ssthreshold设为cwnd/2
- cwnd设为1
- 即一旦发生超时重传就重新进入慢启动
快速重传
- 当接收方发现丢了一个中间包时,会发送三次丢失包的ack,发送方收到后就会快速重传丢失的包
tcp认为这时候拥塞并不严重,只丢了一小部分包,于是
- cwnd = cwnd/2
- ssthreshold变为cwnd
- 然后进入快速恢复算法
快速恢复
- cwnd = ssthresold+3
- 重传丢失的数据包
- 如果再收到重复的ack,那么cwnd+1
- 收到新的ack后,cwnd变为ssthreshold,然后进入拥塞避免算法
流量控制
概念
- 流量控制是基于滑动窗口实现的,tcp通过让接收方指明希望从发送方接收的数据大小(窗口大小)来进行流量控制
问题
描述
- 接收方收到了太多数据,暂时不能接收数据了,于是返回了window大小为0
- 发送方发现window大小为0,于是暂时不再发送数据包了
- 接收方处理完数据,可以继续处理了,于是在之前已处理完的数据包的应答报文中更新窗口大小,但是该应答报文丢失了,导致接收方没能收到,于是就一直不发送新的数据包了,出现了死锁
解决方法
- tcp为每个连接设定一个持续计时器,只有发起连接的一方从对方收到零窗口通知,就启动计时器;如果持续计时器超时,就会发送窗口探测报文,对方会给出自己现在接收窗口的大小
- 窗口探测次数一般为3次,每次大约30-60秒,如果三次后窗口还是0,有的tcp实现会发起RST报文来中断连接
糊涂窗口综合症
发送方
- 发送方虽然知道窗口很大,但是每次都只发送很少的数据
接收方
- 接收方太忙,每次都只能从window中取出很少的数据,然后通知发送方,这样发送方每次也只发送很少的数据
问题
- 每次都只传输小包,效率低
解决方法
让接收方不通知小窗口给发送方
当窗口大小小于min(mss,(缓存空间/2))时,就会向发送方通知窗口为0,阻止发送方后续发送数据过来
- 注mss,Maximum Segment Size,最大报文长度,MSS是TCP报文段中的数据字段的最大长度,不包括TCP首部的长度
让发送方不发送小包
Nagel算法
发送条件
- 等到窗口大小>=mss或数据大小>=mss
- 收到之前发送数据的ack应答
- 满足发送条件的两点才会发送
设置关闭
- Nagel算法默认开启,若想要关闭,需要在socket设置TCP_NODELAY来关闭。没有全局参数,需要每个应用根据自己的特点来关闭
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。