libjingle源码解析(6)-【PseudoTcp】建立UDP之上的TCP(4):超时与重传

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

超时与重传

 

    TCP是面向连接的可靠的运输层。当数据丢失时,TCP需要重传包。TCP通过设置定时器解决这种问题。

    对每个连接,TCP4个不同的定时器:

        1)重传定时器:用于当希望收到另一端的确认,而没有收到时。

        2)坚持定时器:使窗口大小信息保持不断流动。

        3)保活定时器:可检测空闲连接另一端何时崩溃或重启。

        4)2MSL定时器:测量TIME_WAIT状态的时间。

 

    PTCP本身是没有提供定时器的,而通过方法GetNextClock让调用者获取下一个定时器触发的时机,当定时器触发下一个超时时,需要调用方法NotifyClock。

 

超时时间设置

 

    TCP设置获得确认ACK包的超时时间设置序列可能为1.5S3S6S12S24S48S64S,当超时持续时间多于9分钟时,TCP会被复位(RST),即“指数退避”。

    那么这个超时值是怎么计算呢?

    如果能很好的估计RTT话,如果确认包在一个RTT之内没有收到回报,那么可以认为丢包发生。

    TCP最初的RTT估算方法为

        R = aR+(1-a)M

    其中平滑因子a取为90%M表示这次测量的RTT,即这个包发送到获取ACK的时间间隔。

    这个算法通过平滑因子来避免R的值受新的M的浮动过大的影响。然而这恰恰在RTT浮动比较大的连接中无法及时的反应连接情况。并且网络处于饱和状态时,频繁重传会导致火上烧油。Jacobson对此设计了新的算法:

        Err = M - A

        A = A+g*Err

        D = D + h(|Err| -D)

        RTO = A + 4D

    增量g0.125(1/8)Err为上一个得到的值和新的RTT的差。A为上一个测到的增量后的数据,h0.25

RTT变化大时,Err也会变大,导致D也会变大,导致RTO快速上升。某一次连接的估值和真正的RTT关系估下:

 

 

     PTCP实现如下:

     PTCP设置最大超时时间为60S。当收到ACK时,计算RTT是通过PTCP头部的TimeStamp差值计算,所以Karn算法在此不管用。RTO的算法和上面所述一致:

         1)Err = rtt - m_rx_srtt

         2)D=D+0.25*(abs(Err-D))

         3)m_rx_srtt = m_rx_srtt + err/8

         4)RTO = m_rx_srtt+D

     下面的代码实现,有一定的不同,但仔细分析和上面算法是一致的。

 

 

 

[cpp]   view plain copy
  1. bool PseudoTcp::process(Segment& seg) {  
  2. ......  
  3.  // Check if this is a valuable ack  
  4.   if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) {  
  5.     // Calculate round-trip time  
  6.     if (seg.tsecr) {  
  7.       long rtt = talk_base::TimeDiff(now, seg.tsecr);//计算RTT  
  8.       if (rtt >= 0) {  
  9.         if (m_rx_srtt == 0) {  
  10.           m_rx_srtt = rtt;  
  11.           m_rx_rttvar = rtt / 2;  
  12.         } else {  
  13.           m_rx_rttvar = (3 * m_rx_rttvar + abs(long(rtt - m_rx_srtt))) / 4;  
  14.           m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;  
  15.         }  
  16.         m_rx_rto = bound(MIN_RTO, m_rx_srtt +  
  17.             talk_base::_max<uint32>(1, 4 * m_rx_rttvar), MAX_RTO);  
  18.       } else {  
  19.         ASSERT(false);  
  20.       }  
  21.     }  
  22. ......  
  23. }  


 

 

    当重传后,仍然超时时,PTCP也采用指数退避算法。

拥塞避免算法

 

    拥塞避免算法通常和慢启动算法一起使用,主要是限制发送方的流量。慢启动的目的是,不要过快的发送数据导致中间的路由器填满缓冲,而拥塞避免算法是当发现到网络被拥塞时限制发送方处理丢失分组的一种方法。

    拥塞避免算法和慢启动算法同时在一个连接上维护两个变量cwndssthresh。

        1)对一个给定连接cwnd初始化为1。

        2)当拥塞发生时(超时或者受到重复的第三个ack)时ssthreth取当前窗口的一半,如果超时引起的拥塞,则cwnd取为1。

        3)当新的数据包受到确认时,如果cwnd<ssthreth则进行慢启动算法,否则cwnd在每个确认增加1/cwnd

 

快速重传与快速恢复算法

 

     为什么上面判断拥塞时,获得三个以上重复的ACK时,认为产生拥塞了呢?

     因为,当接收方收到失序的报文段时,立即发送需要收到的下一个报文段,然而发送方发送两个以上报文时,因报文的路由不一样,会产生短暂的失序,为了避免因此而产生的重传,把拥塞判断设置为3个以上。

     当收到三个以上重复报文段时,发送方认为此包被丢失,于是立即重传丢失报文段,不会等到超时定时器溢出。这就是快速重传算法。

 

     当发送方重传后,会持续发送后面没有发送的数据,而不启动慢启动,等待ACK,是因为发送方收到了连续的3个以上ACK说明,接收方收到了3个以上数据报文,并缓存起来了。这就是快速恢复算法,实现如下:

        1)当收到3个重复ACKssthreth设置为当前窗口的一半,并cwnd设置为ssthresh+3。

        2)每次收到另一个重复的ACK时,cwnd增加一个报文段并重传。

        3)当下一个ACK到达时cwdn设置为ssthreth,即采用拥塞避免,速率减半。

    对于重传PTCP有一点不同,就是上述第一步,当收到重复3ACK时,ssthresh设置为还未确认的字节数的一半。

 

[cpp]   view plain copy
  1. bool PseudoTcp::process(Segment& seg) {  
  2. ......  
  3.     if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) {//当收到合法的ACK时  
  4. ......  
  5.     if (m_dup_acks >= 3) {//如果进行过重传  
  6.       if (m_snd_una >= m_recover) { // 时重传后的数据确认  
  7.         uint32 nInFlight = m_snd_nxt - m_snd_una;//未确认数据  
  8.         m_cwnd = talk_base::_min(m_ssthresh, nInFlight + m_mss); // cwnd设置为ssthreth  
  9.         m_dup_acks = 0;//重复ACK计数器清零  
  10.       } else {  
  11.         if (!transmit(m_slist.begin(), now)) {//慢启动、继续传送  
  12.           closedown(ECONNABORTED);  
  13.           return false;  
  14.         }  
  15.         m_cwnd += m_mss - talk_base::_min(nAcked, m_cwnd);  
  16.       }  
  17.     } else {  
  18.       m_dup_acks = 0;  
  19.       // Slow start, congestion avoidance  
  20.       if (m_cwnd < m_ssthresh) {//慢启动  
  21.         m_cwnd += m_mss;  
  22.       } else {  
  23.         m_cwnd += talk_base::_max<uint32>(1, m_mss * m_mss / m_cwnd);//拥塞避免,增加1/cwnd  
  24.       }  
  25.      }  
  26.     }  
  27.     else if (seg.ack == m_snd_una) {  
  28.       // !?! Note, tcp says don't do this... but otherwise how does a closed window become open?  
  29.       m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale;  
  30.       // Check duplicate acks  
  31.       if (seg.len > 0) {  
  32.         // it's a dup ack, but with a data payload, so don't modify m_dup_acks  
  33.       } else if (m_snd_una != m_snd_nxt) {  
  34.         m_dup_acks += 1;  
  35.         if (m_dup_acks == 3) { //当收到3个重复的ACK时进行快速重传  
  36.           if (!transmit(m_slist.begin(), now)) {  
  37.             closedown(ECONNABORTED);  
  38.             return false;  
  39.           }  
  40.           m_recover = m_snd_nxt;  
  41.           uint32 nInFlight = m_snd_nxt - m_snd_una;  
  42.           m_ssthresh = talk_base::_max(nInFlight / 2, 2 * m_mss);//ssthresh设置为2个MSS和cwnd的最小值  
  43.           m_cwnd = m_ssthresh + 3 * m_mss;//cwnd设置为ssthresh加3  
  44.         } else if (m_dup_acks > 3) {  
  45.           m_cwnd += m_mss;//当收到发送重传后的重复的ACK时,只增加一个MSS,即快速恢复算法  
  46.         }  
  47.       } else {  
  48.         m_dup_acks = 0;  
  49.       }  
  50.     }  
  51. ......  
  52. }  


 

 

重新分组

    当TCP超时重传时,可以允许以更大的且不大于MSS的报文发送,即合并后续的数据一起发送,PTCP也是如此处理的。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
77 2
|
3天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
3天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
3天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
4天前
|
监控 网络协议 网络性能优化
不再困惑!一文搞懂TCP与UDP的所有区别
本文介绍网络基础中TCP与UDP的区别及其应用场景。TCP是面向连接、可靠传输的协议,适用于HTTP、FTP等需要保证数据完整性的场景;UDP是无连接、不可靠但速度快的协议,适合DNS、RIP等对实时性要求高的应用。文章通过对比两者在连接方式、可靠性、速度、流量控制和数据包大小等方面的差异,帮助读者理解其各自特点与适用场景。
|
14天前
|
存储 网络协议 安全
用于 syslog 收集的协议:TCP、UDP、RELP
系统日志是从Linux/Unix设备及网络设备生成的日志,可通过syslog服务器集中管理。日志传输支持UDP、TCP和RELP协议。UDP无连接且不可靠,不推荐使用;TCP可靠,常用于rsyslog和syslog-ng;RELP提供可靠传输和反向确认。集中管理日志有助于故障排除和安全审计,EventLog Analyzer等工具可自动收集、解析和分析日志。
|
27天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
54 12
|
22天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
4天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
29天前
|
网络协议
网络通信的基石:TCP/IP协议栈的层次结构解析
在现代网络通信中,TCP/IP协议栈是构建互联网的基础。它定义了数据如何在网络中传输,以及如何确保数据的完整性和可靠性。本文将深入探讨TCP/IP协议栈的层次结构,揭示每一层的功能和重要性。
61 5

推荐镜像

更多