kcp协议是传输层的一个具有可靠性的传输层ARQ协议。它的设计是为了解决在网络拥堵情况下tcp协议的网络速度慢的问题。kcp力求在保证可靠性的情况下提高传输速度。kcp协议的关注点主要在控制数据的可靠性和提高传输速度上面,因此kcp没有规定下层传输协议,一般用udp作为下层传输协议,kcp层协议的数据包在udp数据报文的基础上增加控制头。当用户数据很大,大于一个udp包能承担的范围时(大于mss),kcp会将用户数据分片存储在多个kcp包中。因此每个kcp包称为一个分片。

  为了提供可靠性,kcp采用了重传机制。为实现重传机制,kcp为每个分片分配一个唯一标识,接收方收到一个包后告知发送方接到的包的序号,发送方接到确认后再继续发送。而如果发送方在一定时间内(超时重传时间)没有接到确认,就说明数据包丢失了,发送方需要重传丢失的数据包,所以发送方会把待确认的数据缓存起来,方便重传。

  停等的重传机制发送一个包后必须等待确认后再发下一个包,传输速度较慢,所以为了提高发送速度,发送方可以不必再每发送一个包后就进行等待确认,而是可以发送多个包出去,然后等待接收方一一确认。又由于接收方不可能同时处理无限多的数据,因此需要限制发送方往网络中发送的数据数量。因此接收方限制发送方在未收到确认之前只能发送wnd大小的数据,这个机制叫做滑动窗口机制。kcp采用滑动窗口机制来提高发送速度。由于UDP在网络中的传输是不可靠的,因此会出现丢包和包的乱序。kcp是可靠的保证数据有序的协议,所以为了纠正包的乱序。接收方维护一个接收窗口。接收窗口有一个起始序号rcv_nxt以及尾序号rcv_nxt+rcv_wnd。如果接收窗口收到序号为rcv_nxt的分片那么rcv_nxt就加一,形象一点的说法是滑动窗口右移,并把该数据放入接收队列供应用层取用。如果收到的数据在窗口范围内但不是rcv_nxt那么就把数据保存起来,等收到rcv_nxt序号的分片时再一并放入接收队列供应用层取用。

  当网络拥堵严重时,会发生丢包,丢包发生时kcp为了保证可靠性需要重传数据。而发送方需要判断什么时候发生了丢包,以及丢了哪些包。为了解决这个问题,发送方为缓存队列中的每个包设置了包序号和超时重传时间。当检测到当前时间超过了分片的超时重传时间,该分片还没有得到确认时就会触发该分片的超时重传

  数据在网络中的传输时间是不固定的,因此超时重传时间比较长。而为了尽早地判断出数据包的丢失,kcp引入了快速重传机制。快速重传机制工作原理是,当发送方发送了n,n+1,n+2...等等包出去后,接收方没有接收到n,而接收到n+1,n+2..等等n号包之后的包,这时因为n号包之后的包都已经接收到了,而n号包还没有接收到,所以可以认为n号包已经丢失了,告知发送方可以进行快速重传。kcp为了支持快速重传,接收方需要告诉发送方,哪些包已经成功收到了,哪些包没有收到。因此接收方返回发送方的确认数据(ack)中包含以下信息:接收窗口左端的序号rcv_nxt,接收到的大于rcv_nxt的包序号sn。rcv_nxt的含义是接收方已经成功按顺序接收了rcv_nxt序号之前的所有包,大于rcv_nxt的序号sn表示的是在接收窗口内的不连续的包。发送方接收到接收方发过来的数据时,首先解析rcv_nxt,把发送缓存中所有小于rcv_nxt序号的包全部移除掉(因为这些包全都都已经正确接收了)。然后再解析sn,遍历发送缓存,找到所有序号小于sn的包,这些包就是可能在网络中已经丢掉了的包,只是可能,因为有可能这些包只是拥堵在了网络中,需要更长的时间到达,所以这里我们设置一个快速重传的门限,对每个分片维护一个快速重传的计数,每收到一个ack解析sn后找到了一个分片,就把该分片的快速重传的计数加一,如果该计数达到了快速重传门限,那么就认为该分片已经丢失,可以触发快速重传,该门限值在kcp中可以设置,tcp中是3。

  丢包发生时,由于滑动窗口的存在,假设第n个包丢失了,但是此时n+1,n+2号包却已经传输成功了,此时最好只重传丢失的n号包,而不重传成功传输的n+1,n+2号包,这个机制叫做选择重传,选择重传的关键在于接收方要告知发送方哪些包已经收到了,哪些包没有收到,为了最小化数据量,接收方可以告诉发送方哪些包已经按序收到了,哪些包是收到的但是不连续。所以返回的ack中包含rcv_nxt和sn。rcv_nxt代表收到的所有连续的包,sn代表哪些不连续的包收到了,那么根据这两个参数可以计算出来没有收到的包的序号。

  当网络实在很拥堵的时候(一般由于网络消息太多,堵车了),kcp会限制发送方发送的数据量,这叫做拥塞控制,拥塞控制就是告诉发送方,网络太堵了,应该少发一些数据,因此在滑动窗口的机制上引入了拥塞窗口,也就是说发送发发送的数据不得超过拥塞窗口,拥塞窗口的大小会随网络情况而变快,网络快拥塞窗口就大,反之同理。

  那么拥塞窗口应该等于多少呢?解决这一问题的原则是,让网络充分被利用,但是不能堵塞,这里引入了慢启动机制,慢启动也就是控制拥塞窗口从0开始增长,随着数据不断地成功传输,拥塞窗口逐渐增大,直至达到饱和,也就是网络的收发平衡。为了快速达到网络的收发平衡,拥塞窗口采用倍数增长。也就是每成功发送一个数据拥塞窗口加一,举个例子,窗口大小为1时,发送一个数据,成功后窗口变成2,之后发送两个数据出去,成功接收后窗口大小变为4。为了方便让更多的用户连入网络时,网络能有足够的流量提供给用户,还可以设置拥塞门限,拥塞门限值就是当用户拥塞窗口快速增长到门限值后就减慢增加速度,缓慢增长,腾出流量给其它用户。

  但是当网络很拥堵的情况下,导致发送数据出现重传时,这时说明网络中消息太多了,用户应该减少发送的数据,也就是拥塞窗口应该减小。怎么减小呢,在快速重传的情况下,有包丢失了但是有后续的包收到了,说明网络还是通的,这时采取拥塞窗口的退半避让,拥塞窗口减半,拥塞门限减半。减小网络流量,缓解拥堵。当出现超时重传的时候,说明网络很可能死掉了,因为超时重传会出现,原因是有包丢失了,并且该包之后的包也没有收到,这很有可能是网络死了,这时候,拥塞窗口直接变为1,不再发送新的数据,直到丢失的包传输成功。

  在上述原理之下,kcp为了提高传输速度,还可以有许多选项供用户选择:

    kcp的拥塞控制可以取消

    ack回复可以设置成无延迟ack回复

    kcp的快速重传门限可以控制

  总之,kcp采取一系列措施尽量提高网络传输速率,在网络实时性和可靠性要求比较高的场景下可以考虑kcp协议代替tcp协议。

kcp协议详解的更多相关文章

  1. HTTP协议详解(转)

    转自:http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HTTP是一个属于应用层的面向对象的 ...

  2. HTTP协议详解

    Author :Jeffrey 引言 HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和 扩展. ...

  3. 动态选路、RIP协议&&OSPF协议详解

    动态选路.RIP协议&&OSPF协议详解 概念 当相邻路由器之间进行通信,以告知对方每个路由器当前所连接的网络,这时就出现了动态选路.路由器之间必须采用选路协议进行通信,这样的选路协议 ...

  4. ASP.NET知识总结(3.HTTP协议详解)

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  5. 接口测试之HTTP协议详解

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  6. 计算机网络(12)-----HTTP协议详解

    HTTP协议详解 http请求 http请求由三部分组成,分别是:请求行.消息报头.请求正文 (1)请求行 请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Metho ...

  7. OSPF协议详解

    CCNP OSPF协议详解 2010-02-24 20:30:22 标签:CCNP 职场 OSPF 休闲 OSPF(Open Shortest Path Fitst,ospf)开放最短路径优先协议,是 ...

  8. HTTP协议详解(真的很经典)

    HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和 扩展.目前在WWW中使用的是HTTP/1.0 ...

  9. HTTP协议详解--转载http://blog.csdn.net/gueter/article/details/1524447

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

随机推荐

  1. 从使用 KVO 监听 readonly 属性说起

    01.KVO 原理 KVO 是 key-value observing 的简写,它的原理大致是: 1.当一个 object(对象) 有观察者时候,动态创建这个 object(对象) 的类的子类(以 N ...

  2. iOS 即时通讯,从入门到 “放弃”?

    原文链接:http://www.jianshu.com/p/2dbb360886a8 本文会用实例的方式,将 iOS 各种 IM 的方案都简单的实现一遍.并且提供一些选型.实现细节以及优化的建议. — ...

  3. 【js】typeof与instanceof

    typeof 运算符 返回一个用来表示表达式的数据类型的字符串. typeof[()expression[]] ; expression 参数是需要查找类型信息的任意表达式. 说明 typeof 运算 ...

  4. VS2012开发cocos游戏遇到问题汇总

    1.编译成android时.须要改动jni/android.mk,每一个cpp都改动一下太麻烦,能够让他自己主动识别. # 遍历文件夹及子文件夹的函数 define walk $(wildcard $ ...

  5. [svc]磁盘接口与RAID

    一 磁盘接口 IDE 传统家用: /dev/hda1 SISC 传统服务器: /dev/sdb1 SATA 现在家用 SAS 现在服务器用 FC(光纤通道) 高级服务器 注意: 分区编号,1-4只能给 ...

  6. 【Android】7.8 MyDemos项目的结构和主界面相关代码

    分类:C#.Android.VS2015: 创建日期:2016-02-17 一.简介 上一讲已经说过,系统升级为Win10后,重新创建了一个新的项目:MyDemos,并把前7章合并到了这个项目中,这次 ...

  7. netty深入学习之中的一个: 入门篇

    netty深入学习之中的一个: 入门篇 本文代码下载: http://download.csdn.net/detail/cheungmine/8497549 1)Netty是什么 Netty是Java ...

  8. 【ActiveMQ】ActiveMQ在CentOS的搭建与使用

    下载 到ActiveMQ官网,找到下载点. 目前, 官网为http://activemq.apache.org/. 我们下载目前最新的版本吧,当前的Linux版本下载地址之一为:http://apac ...

  9. 双系统中ubuntu的安装方法

    双系统中ubuntu的安装方法 注意:给电脑安装双系统时,一定要先装Windows系统,再安装Linux系统! 原因是电脑开机后,要先执行一段bootloader引导程序:再由引导程序启动操作系统.W ...

  10. gulp——myself配置

    var gulp = require('gulp'), uglify = require('gulp-uglify'), concat = require('gulp-concat'); var pu ...