原标题:KCP-GO源码解析
社区零食大礼包限量发售:
(豆干,牛肉丝,创意福袋等四川特产)
KCP-GO源码解析 概念
ARQ:自动重传请求(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层的错误纠正协议之一.
RTO:Retransmission TimeOut
FEC:Forward Error Correction
kcp简介
kcp是一个基于udp实现快速、可靠、向前纠错的的协议,能以比TCP浪费10%-20%的带宽的代价,换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发。查看官方文档kcp
kcp-go是用go实现了kcp协议的一个库,其实kcp类似tcp,协议的实现也很多参考tcp协议的实现,滑动窗口,快速重传,选择性重传,慢启动等。
kcp和tcp一样,也分客户端和监听端。
1+-+-+-+-+-+ +-+-+-+-+-+
2| Client || Server |
3+-+-+-+-+-+ +-+-+-+-+-+
4|------ kcp data ------>|
5|
kcp协议layer model
1+----------------------+
2| Session |
3+----------------------+
4| KCP(ARQ) |
5+----------------------+
6| FEC(OPTIONAL) |
7+----------------------+
8| CRYPTO(OPTIONAL)|
9+----------------------+
10| UDP(Packet) |
11+----------------------+
KCP header
KCP Header Format
14112(Byte)
2+---+---+---+---+---+---+---+---+
3| conv |cmd |frg|wnd |
4+---+---+---+---+---+---+---+---+
5|ts | sn |
6+---+---+---+---+---+---+---+---+
7| una |len |
8+---+---+---+---+---+---+---+---+
9||
10+ DATA +
11||
12+---+---+---+---+---+---+---+---+
13
代码结构
1src/vendor/github.com/xtaci/kcp- go/
2├── LICENSE
3├── README.md
4├── crypt. go加解密实现
5├── crypt_test. go
6├── donate.png
7├── fec. go向前纠错实现
8├── frame.png
9├── kcp- go.png
10├── kcp. gokcp协议实现
11├── kcp_test. go
12├── sess. go会话管理实现
13├── sess_test. go
14├── snmp. go数据统计实现
15├── updater. go任务调度实现
16├── xor. goxor封装
17└── xor_test. go
着重研究两个文件kcp.go和sess.go
kcp浅析
kcp是基于udp实现的,所有udp的实现这里不做介绍,kcp做的事情就是怎么封装udp的数据和怎么解析udp的数据,再加各种处理机制,为了重传,拥塞控制,纠错等。下面介绍kcp客户端和服务端整体实现的流程,只是大概介绍一下函数流,不做详细解析,详细解析看后面数据流的解析。
kcp client整体函数流
和tcp一样,kcp要连接服务端需要先拨号,但是和tcp有个很大的不同是,即使服务端没有启动,客户端一样可以拨号成功,因为实际上这里的拨号没有发送任何信息,而tcp在这里需要三次握手。
1DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int)
2V
3net.DialUDP( "udp", nil, udpaddr)
4V
5NewConn()
6V
7newUDPSession() {初始化UDPSession}
8V
9NewKCP() {初始化kcp}
10V
11updater.addSession(sess) {管理session会话,任务管理,根据用户设置的 internal参数间隔来轮流唤醒任务}
12V
13go sess.readLoop()
14V
15go s.receiver(chPacket)
16V
17s.kcpInput(data)
18V
19s.fecDecoder.decodeBytes(data)
20V
21s.kcp.Input(data, true, s.ackNoDelay)
22V
23kcp.parse_data(seg) {将分段好的数据插入kcp.rcv_buf缓冲}
24V
25notifyReadEvent()
26
客户端大体的流程如上面所示,先Dial,建立udp连接,将这个连接封装成一个会话,然后启动一个go程,接收udp的消息。
kcp server整体函数流
1ListenWithOptions()
2V
3net.ListenUDP()
4V
5ServerConn()
6V
7newFECDecoder()
8V
9go l.monitor() {从ch