KCP协议

前提

        在网络中,我们认为传输是不可靠的,但是在很多实际的场景中,我们需要得到可靠的数据。

        得到可靠的数据:数据能够正确到达并且有序。(注意这里有两个条件,一个是有序,一个收到)。

        为了达到这个目的,操作系统的协议栈的传输层采用了ARQ协议TCP采用的就是AQR协议。

        为什么通常我们认为网络上的传输是不可靠的?(GPT回答,这里我们稍微了解一下)

        1.数据包丢失:在网络传输过程中,数据包可能会因为各种原因丢失,例如网络拥塞、错误路由等,这会导致传输中部分数据丢失或损坏。

        2.延迟和抖动:网络延迟是指数据从发送端到接收端所需的时间,而抖动则是指延迟时间的不稳定性。由于网络拥塞、信号干扰等原因,延迟和抖动可能会导致传输中的数据出现乱序、重复或延迟问题。

        3.误码和校验错误:在数字信号传输中,由于噪音、干扰或设备故障等原因,数据可能发生位错误。校验机制可以检测并纠正这些错误,但它们并不能完全消除误码问题。

        4.不可靠连接:在TCP/IP协议中,通常使用面向连接的方式进行数据传输,尽管TCP协议提供了一些可靠保证机制(如确认应答、重传等),但仍然无法保证绝对可靠的传输。

ARQ协议 

        这里说下个人观点:不要被计算机里很多高大上的名词吓到了,换一个角度思考,事务总是在发展的,很多规则的由来是对缺陷的补丁。

        ARQ(Automatic Repeat-reQuest)协议,顾名思意自动重传请求其实说到这里,作为一个正常的人都应该能猜得八九不离十了,我们前面说到现需要保持按序收到,实现得有这个序,还需要重传,怎么重传,什么时候重传就是需要解决的问题了?很自然,这么想来其实很多东西都没有想得那么复杂,只是为了解决某种问题而提出的特定的方法。那么作为一名程序员,感觉越来越深刻了,以为很牛的大佬,不一定是了解很多高深的技术,而是能解决特定场景下的特定问题才是根本。

        定义:ARQ协议,即自动重传请求,是传输层的错误纠正协议之一,它通过使用确认和超时两个机制,在不可靠的网络上实现可靠的信息传输。

        ARQ协议主要有3中模式:

        1.停等式

        2.回退n帧

        3.选择性重传


补充:我们这里稍微做一点补充,后面需要介绍一些名词,对于一些朋友会比较陌生。

通常保证可靠传输有以下几种机制:

1.ACK机制 (确认机制)

2.重传机制 (什么时候重传、如何重传) 

3.序号机制

4.重排机制

5.窗口机制  (流量控制、带宽控制)


ARQ协议 - 等停式

        这种方式是最容易想到的,就是A发一个数据给B,然后A发送后开始倒计时,在倒计时结束之前,还没有收到B发过来的ACK确认数据包,则A认为B没有收到刚才发送的数据,则A将重发。(大白话总结)

        工作原理(专业说法):

        1.发送方对接收方发送数据包(分组),然后等待接收方回复ACK并且开始计时。

        2.在等待过程中,发送方停止发送新的数据包(分组)。

        3.当数据包没有成功被接收方接收,接收方不会发送ACK。这样发送方在等待一定时间后,重新发送数据包。

        很明显能够看出这样存在很大的缺陷,耗时很严重。A必须等B,那么在网络环境很糟糕的情况下,A几乎每次都需要等到一定是时间。(这种方法虽然比较好的解决方案,但是在实际应用中,有时候我们可以用这种方式对重要信息进行补发,或许是一个比较好的处理方案,而且操作起来很简单。我们很容易想到心跳机制,其实跟这个很像,心跳机制可以用来确认对端的状态而做相应的处理,在长期运行过程中出现宕机等问题时是一个不错的选择)。

        缺点:较长的等待时间导致低的数据传输速度。


 ARQ协议 - 回退n帧

        前面我们说到我们带着事物是发展的眼光去看待这个问题,等停式是发一个数据包就等待,发一个数据包就等待,这样会有较长的等待时间导致低的数据传输速度。针对这个缺点,提出连续的ARQ协议会连续发送一组数据包,然后再等待这些数据包的ACK。

        好,说到这里,我们再来考虑一个问题,现在改成了连续发送一组数据包,那么我们怎么知道哪些包到达了,哪些没有达到,哪些先到达了,哪些后到达呢?很自然,我们可以对每组数据进行标号(也就是上面说的序号机制)。这样一来,对于发送方而言就能够确认哪些分组收到了ACK,哪些没有收到ACK,我们就能够知道哪些分组丢失了需要重传。对于接收方而言就能够按标号顺序进行排序,我们就能够知道怎么对数据进行组织了。

        回退n帧:回退n步协议允许发送方在等待超时的间歇,可以继续发送分组。所有发送的分组,都带有序号。

        回退n帧-发送方:

        1.上层的调用。上层调用相应send()时,发送方首先要检查发送窗口是否已满

        2.接收ACK。

        3.超时。若出现超时,发送方将重传所有已发送但未被确认的分组。

(在这种方式中,对于序号为n的分组的确认采取累积确认的方式,表明接收方已正确接收到序号n以前(包括n)的所有分组)--> 这里可能会有一些疑惑,怎么就能确认n以前的呢?不急,我们看接收方怎么回应ACK的,就自然能够理解了。

        回退n帧-接收方:

        对于接收方来说,若一个序号为n的分组被正确接收,并且按序,则接收方会为该分组返回一个ACK给发送方,并且将该分组中数据交付给上层。在其他情况下,接收方都会丢弃分组。(这里已经能够解释发送方接收ACK时的序号n,就能保证n和n以前的都认为被正确接收了,因为可能n之前的一些ACK包没有达到发送方)

        若分组n已接收并且交付,那么所有序号比n小的分组也已经完成了交付。因此回退n帧采用累积确认是一个很自然的选择。--> 那么,我们这里是不是可以只需要确认在一定时间内确认最大n就行了,这样能更快,不需要每个n都确认。确实协议里也是这么做的,发送方在发完一个窗口里的所有分组后,会检查最大的有效确认,然后从最大有效确认的换一个分组开始重传。

-------------------------------------------------------------------------------------------------------------------------

补充:这里我们稍微做个补充,这里说的窗口就是前面说的窗口机制。通常在通信的双方会各自维护一个窗口,可以把窗口理解为缓冲区,通常发送缓冲区略小于接收缓冲区,在传输层会自动做一些调整的,窗口存在的意义主要是为了平衡生产和消费之间不平衡的问题

-------------------------------------------------------------------------------------------------------------------------

如图所示:最大收到的ACK确认是2号包,下次从2号后面一个开始传。


ARQ协议-选择重传

        虽然回退n帧的方式改善了停等式协议中时间等待较长的缺陷,但它依旧存在着性能问题。特别是当窗口长度很大的时候,会使效率大大降低(在网络很不好的情况下,16k的窗口0号没收到,需要重发16k。8K的窗口0号没收到,需要重发8K,发送16K数据与发送8K数据所需要的时间显然是不一样的)。

        其实很明显,回退n帧的方式,假设1、2、3、4,收到了1、3、4,本质上来说,只需要对2进行重发,没有必要将2、3、4都进行重发。

        选择重发协议就是这么做的,它通过让发送方仅重传再接收方丢失或损坏了的分组,从而避免了不必要的重传,提高了效率。

        选择重传-发送方

        1.从上层收到数据。当从上层收到数据后,发送方需检查下一个用于该分组的序号。若序号在窗口中则将数据发送。

        2.接收ACK。若收到ACK,且该分组在窗口内,则发送方将那个被确认的分组标记位已接收。若该分组序号等于基序号,则窗口序号向前移动到具有最小序号的未确认分组处。若窗口移动后并且有序号落在窗口内的未发送分组,则发送这些分组。

        3.超时。若出现超时,发送方将重传已发出但还未确认的分组。在选择重发协议中每个分组都有独立的计时器。

        选择重传-接收方

        接收方接收时,如果接收到的数据不是所需要的序号,则将被暂时缓存,并发送一个ACK。[4、5、6],收到了4号,收到了6号,先缓存起来,等收到5号之后再从缓存中取出6号,组成456。如果长时间没有回应5号的ACK,则发送方将会重传5号分组。

        对于接收方来说,若一个分组正确接收而不管其是否按序,则接收方会为该分组返回一个ACK给发送方。失序的分组将被缓存,直到所有丢失的分组的被收到,这时才可以将一批分组按序交付给上层。

RTT和RTO

RTO:重传超时时间

RTT:往返时延。表示从发送端发送数据开始,到发送端收到来自接收端的确认,总共经历的时延。

由三部分组成:

1.链路的传播时间

2.末端系统的处理时间

3.路由器缓存中的排队和处理时间

其中,前两个部分的值对于一个TCP连接相对固定,路由器缓存中的排队和处理时间会随着整个网络拥塞程度的变化而变化。所以RTT的变化在一定程度上反应网络的拥塞程度。

流量控制

        流量控制说白了就是为了减少丢包的情况,丢包是需要重发的,会浪费网络资源。前面我们提到发送端和接收端都会维护一个窗口(缓冲区),流量控制就是已这个窗口为基准,确保发送的数据包在接收端能够正常被接受或者进入缓冲区,减少接收方缓冲区堆满而丢包。

        双方在通信的时候,发送方的速率与接收方的速率是不一定相等的,如果发送方的发送速率太快,会导致接收方处理不过来,这时候接收方只能把处理不过来的数据存在缓存区里(失序的也存在缓存区)接收缓存。如果缓存区满了发送方还在疯狂着发送数据,接收方只能把收到的数据包丢掉,大量的丢包会极大的;浪费网络资源,因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。

        总的来说,对发送方发送速率的控制,称之为流量控制。它取决于接收方的窗口剩余大小。

流量控制机制

        1.接收方每次收到数据包,可以在发送确认报文的时候,同时告诉发送方自己的缓存区还剩余多少是空闲的,我们也把缓存区的剩余大小称之为接收方的窗口大小,通常用win字段表示接收方窗口大小。

        2.发送方收到之后,便会调整自己的发送速率,也就是调整自己发送窗口的大小,当发送方收到接收窗口的大小为0时,发送方就会停止发送数据,防止出现大量丢包情况的发生。

窗口探测机制

        图中标明了窗口探测,这个是什么意思呢?现在我们已经知道了流量控制方式,当win=0时,发送方会停止发送,那什么时候重新进行发送呢?当然是win>0时,再重新进行发送。

        这里就有两种方法:

        1.当接收方处理好数据,接收窗口win>0时,接收方发个通知报文区通知发送方,告诉他可以继续发送数据了。当发送方收到窗口大于0的报文时,就继续发送数据。

        2.当发送方收到接收窗口win=0时,这时发送方停止发送报文,并且同时开启一个定时器,每隔一段时间就发一个测试报文询问接收方,打听是否可以继续发送数据了,如果可以,接收方就告诉他此时接收窗口的大小,如果接受窗口大小还是0,则发送方再次刷新启动定时器。

相关问题

1.通信的双方的拥有两个滑动窗口,一个用于接收数据,称之为接收窗口,一个用于发送数据,称之为拥塞窗口(即发送窗口)。指出接收窗口大小的通知我们称之为窗口通告

2.接收窗口大小时根据某种算法动态调整的,不是大小固定的。

3.当接收窗口达到某个值的时候,再增加的话也不会减少丢包的情况,而且还会消耗更多的内存,所以接收窗口的大小必须根据网络环境以及发送发的拥塞窗口来动态调整。

4.接收方在发送确认报文的时候,会告诉发送方自己的接收窗口大小,而发送方的发送窗口会据此设置自己的发送窗口,但这并不意味着他们就会相等。首先接收方把确认报文发出去的时候,就已经开始处理缓存区中的数据了,所以一般情况下接收窗口>=发送窗口

拥塞控制

        拥塞控制和流量控制虽然采取的动作很相似,但拥塞控制与网络的拥堵情况相关联,而流量控制与接收方的缓存状态相关联

        前面我们也说到了,很多东西是为了解决某个问题提出来的具体方案。对于拥塞控制是为了解决拥堵情况提出的解决策略,流量控制是解决接收方接收能力提出的策略。不要把他们搞混了。

网络拥堵情况

        现在我们假设一种情况,A和B之间进行通信,A作为发送方,B作为接收方。前面我们了解到,网络上两台主机之间进行通信,会有ARQ重发机制,当A给B发送分组,当一定时间没有收到B的ACK回应,则A认为该分组丢失了,A会重发。

        现在假设A和B使用的信道很拥挤,在实际情况在是存在这种情况的(很多主机使用这个信道),这时候就会出现拥挤(可以想象下高速堵车的情况),那么A给B发送是数据很可能堵在了半路,但A认为包丢失了,A会重新发送,这么一来就会导致更加拥堵。设想下这个条信道里有很多主机的重发,这是何等恐怖的存在。

5分钟读懂拥塞控制 (qq.com)

 UDP如何可靠

做了这么多铺垫,现在再回到UDP保证可靠传输的方法。

        1.ACK机制

        2.序号机制

        3.重传机制

        4.重排机制

        5.窗口机制

        我们做这些需要在应用层进行保证,协议栈的处理交给操作系统,通常不推荐修改内核源码。这些我们不需要自己去做,有开源的库可以调用。比如常见的KCP和QUIC。

KCP协议

        KCP的具体方法说白了就是将TCP保证可靠的机制移植到了UDP上,KCP相比于TCP或者设计初衷之一就是为了解决在网络拥塞的情况下TCP传输效率慢的问题。并且保证了UDP的可靠性,可以这么说KCP是UDP和TCP的折中取法。

        KCP是一个快速可靠协议,能以比TCP浪费10%-20%大带宽的代价,换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(UDP)的收发,需要使用者自己定义下层数据的发送方式,以回调的方式提供给KCP。连时钟都需要外部传递进来,内部不会有任何一次系统调用。

        TCP是为流量设计的(每秒内可以传输多少KB的数据 --> 带宽),讲究的是充分利用带宽。而KCP是为流速设计的(单个数据从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比TCP快30%-40%的传输速度

KCP数据段格式

        conv:连接号(类型与http的会话ID)。UDP是无连接的,conv用于表示来自于哪个客户端。对连接的一种替代。--> 一个会话记录了一个连接(你可以这么理解),一个会话有很多个包,需要将这些包组装一起形成一个完整的TCP会话。

        cmd:命令名。

        

        frg:分片,用户数据可能会被分为多个KCP包发送出去

        wnd:接收窗口的大小,发送方发送窗口的数据不能超过接收方给出的数值。

        ts: 时间序列

        sn:序列号

        una:下一个可接收的序列号。其实就是确认号,收到sn=10,una=11      

KCP特征        

1.RTO不翻倍

        RTO即重传超时时间,TCP是基于ARQ协议实现的可靠性,KCP也是基于ARQ协议实现的可靠性,但TCP的超时计算是RTO*2,而KCP的超时计算是RTO*1.5,也就是说假如连续丢同一个包3次,TCP第3次重传是RTO*8,而KCP则是RTO*3.375,意味着可以更快地重新传输数据。通过4字节ts计算RTT(往返时延),载通过RTT计算RTO。

2.选择性重传

        TCP丢包是会全部重传从丢的哪个包开始以后的数据,KCP是选择性重传,只重传真正丢失的数据包。并且在KCP的快速重传模(跳过了多少包马上重传,不考虑RTO)式中,不用等待超时(发送端发送了1,2,3,4,5几个包,然后收到远端的ACK1,3,4,5,当收到ACK3时,KCP知道2被跳过了1次,收到ACK4时知道2被跳过了2次,此时可以认为2号丢失,不用等超时,直接重传2号包,大大改善了丢包时的传输速度)。

3.非延迟ACK

        TCP为了充分利用带宽,延迟发送ACK,这样超时计算会算出较大的RTT时间,延长了丢包时的判断过程。KCP的ACK是否延迟发送可以调节。

4.UNA + ACK

        ARQ模型响应有两种,UNA(此编号前所有的包已收到,TCP,这里类型与回退n帧的方式进行重传)和ACK(该包收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,在KCP中,出去单独大ACK包外,所有包都有UNA信息。

5.非退让流控

        KCP正常模式同TCP一样使用公平退让法则,即发送窗口大小由发送缓存大小、接收端剩余接收缓存大小、丢包退让及慢启动这四要素决定。但传送及时性要求很高的小数据时,可以选择只使用发送和接收方缓存区大小来控制发送频率。以牺牲部分公平性及带宽利用率为代价,换取流畅的传输效果。

KCP一些概念

        用户数据:应用层发送的数据

        MTU:最大传输单元。即每次发送的最大数据,1500字节

        RTO:   重传超时时间

        cwnd:  拥塞窗口,表示发送方可以发送多少个KCP数据包。与接收方窗口有关,与网络状况(拥塞控制)有关,与发送窗口有关。

        rwnd:接收方窗口大小,表示接收方还可接收多少KCP数据包

        snd_queue:待发送KCP数据包队列

        snd_nxt:下一个即将发送的kcp数据包序列号

        snd_una:下一个待确认的序列号,即是之前的包接收端都已经收到

KCP的使用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

存钱买房的陈一言

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

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

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

打赏作者

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

抵扣说明:

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

余额充值