├── README-EN.md ├── README.md ├── codec.go ├── empty.s ├── errors.go ├── go.mod ├── go.sum ├── kcp.go ├── kcp_buffer.go ├── kcp_test.go ├── pool.go └── protocol.go /README-EN.md: -------------------------------------------------------------------------------- 1 | # gokcp 2 | gokcp is go implementation based on KCP 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gokcp 2 | gokcp是KCP (https://github.com/skywind3000/kcp) 的Go语言实现。 3 | 4 | gokcp与KCP的不同点在于: 5 | 1. 以位计算方式实现了ack list,好处是简化代码以及节约一个int32的大小。 6 | 2. 实现另外一种RTO的计算方法,算法移植自Linux内核里面TCP RTO计算算法,在慢网速但丢包少的环境下,此算法能少重传大约个位数百分比的数据包。 7 | 8 | # 如何使用 9 | 请参考gouxp: https://github.com/shaoyuan1943/gouxp 10 | -------------------------------------------------------------------------------- /codec.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import "encoding/binary" 4 | 5 | func encode8u(p []byte, c byte) []byte { 6 | p[0] = c 7 | return p[1:] 8 | } 9 | 10 | func decode8u(p []byte, c *byte) []byte { 11 | *c = p[0] 12 | return p[1:] 13 | } 14 | 15 | func encode16u(p []byte, w uint16) []byte { 16 | binary.LittleEndian.PutUint16(p, w) 17 | return p[2:] 18 | } 19 | 20 | func decode16u(p []byte, w *uint16) []byte { 21 | *w = binary.LittleEndian.Uint16(p) 22 | return p[2:] 23 | } 24 | 25 | func encode32u(p []byte, l uint32) []byte { 26 | binary.LittleEndian.PutUint32(p, l) 27 | return p[4:] 28 | } 29 | 30 | func decode32u(p []byte, l *uint32) []byte { 31 | *l = binary.LittleEndian.Uint32(p) 32 | return p[4:] 33 | } 34 | 35 | func encode64u(p []byte, l uint64) []byte { 36 | binary.LittleEndian.PutUint64(p, l) 37 | return p[8:] 38 | } 39 | 40 | func decode64u(p []byte, l *uint64) []byte { 41 | *l = binary.LittleEndian.Uint64(p) 42 | return p[8:] 43 | } 44 | 45 | func min(a, b uint32) uint32 { 46 | if a <= b { 47 | return a 48 | } 49 | return b 50 | } 51 | 52 | func max(a, b uint32) uint32 { 53 | if a >= b { 54 | return a 55 | } 56 | return b 57 | } 58 | 59 | func bound(lower, middle, upper uint32) uint32 { 60 | return min(max(lower, middle), upper) 61 | } 62 | 63 | func timediff(later, earlier uint32) int32 { 64 | return (int32)(later - earlier) 65 | } 66 | 67 | func encodeSegment(data []byte, seg *segment) []byte { 68 | rawseg := encode32u(data, seg.convID) // 4 69 | rawseg = encode8u(rawseg, uint8(seg.cmd)) // 1 70 | rawseg = encode8u(rawseg, uint8(seg.frg)) // 1 71 | rawseg = encode16u(rawseg, uint16(seg.wnd)) // 2 72 | rawseg = encode32u(rawseg, seg.ts) // 4 73 | rawseg = encode32u(rawseg, seg.sn) // 4 74 | rawseg = encode32u(rawseg, seg.una) // 4 75 | rawseg = encode32u(rawseg, uint32(len(seg.dataBuffer))) // 4 76 | return rawseg // total 24 77 | } 78 | -------------------------------------------------------------------------------- /empty.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/gokcp/5b36d4c87f613eaa7f87654d09af0a968aa8b515/empty.s -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrDataInvalid = errors.New("data invalid") 7 | ErrDataTooLong = errors.New("the data too long") 8 | ErrDifferenceConvID = errors.New("difference conv ID") 9 | ErrNoReadableData = errors.New("no readable data") 10 | ErrNoEnoughSpace = errors.New("no enough space to add data") 11 | ) 12 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/shaoyuan1943/gokcp 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/klauspost/reedsolomon v1.9.9 7 | github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= 2 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 3 | github.com/klauspost/cpuid v1.2.4 h1:EBfaK0SWSwk+fgk6efYFWdzl8MwRWoOO1gkmiaTXPW4= 4 | github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 5 | github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54= 6 | github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo= 7 | github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= 8 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 9 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 10 | github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= 11 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 12 | github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 h1:UCU8+cLbbvyxi0sQ9fSeoEhZgvrrD9HKMtX6Gmc1vk8= 13 | github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls= 14 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 15 | golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= 16 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 17 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 18 | golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= 19 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 20 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 21 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 22 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 23 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 24 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 25 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 26 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 27 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 28 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 29 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 30 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 31 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 32 | golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= 33 | golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 34 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 35 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 36 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 37 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 38 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 39 | -------------------------------------------------------------------------------- /kcp.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import ( 4 | _ "unsafe" 5 | ) 6 | 7 | type segment struct { 8 | convID uint32 9 | cmd uint32 // package type 10 | frg uint32 // user data slice number, 0 is last 11 | wnd uint32 // recv window size 12 | ts uint32 // send message timestamp 13 | sn uint32 // sequence number 14 | una uint32 // next message sequence number(recv) 15 | resendTs uint32 // send time stamp 16 | rto uint32 17 | fastACK uint32 // skip ACK times 18 | xmit uint32 19 | dataBuffer []byte 20 | acked bool // flag this segment ack incept 21 | } 22 | 23 | func (seg *segment) reset() { 24 | seg.convID = 0 25 | seg.cmd = 0 26 | seg.frg = 0 27 | seg.wnd = 0 28 | seg.ts = 0 29 | seg.sn = 0 30 | seg.una = 0 31 | seg.resendTs = 0 32 | seg.rto = 0 33 | seg.fastACK = 0 34 | seg.xmit = 0 35 | seg.dataBuffer = seg.dataBuffer[:0] 36 | seg.acked = false 37 | } 38 | 39 | type KCP struct { 40 | convID, mtu, mss, state uint32 41 | lastACK uint32 42 | sendUNA, sendNext, recvNext uint32 43 | ssthresh uint32 44 | rxRTTValue, rxSRTT, rxRTO, rxMinRTO int32 45 | sendWnd, recvWnd, remoteWnd, cwnd uint32 46 | interval, tsFlush, xmit uint32 47 | noDelay bool 48 | updated uint32 49 | probe, tsProbe, probeWait uint32 50 | deadLink, incr uint32 51 | sendQueue, recvQueue []*segment 52 | sendBuffer, recvBuffer []*segment 53 | ackList []uint64 54 | buffer *Buffer 55 | fastResendACK, fastACKLimit uint32 56 | nocwnd, streamMode bool 57 | outputCallback OutputCallback 58 | mdev, mdevMax, rttSN int32 59 | stableNetwork bool 60 | } 61 | 62 | func NewKCP(convID uint32, outputCallbakc OutputCallback) *KCP { 63 | kcp := &KCP{convID: convID, outputCallback: outputCallbakc} 64 | kcp.sendWnd = KCP_WND_SND 65 | kcp.recvWnd = KCP_WND_RCV 66 | kcp.remoteWnd = KCP_WND_RCV 67 | kcp.mtu = KCP_MTU_DEF 68 | kcp.mss = kcp.mtu - KCP_OVERHEAD 69 | kcp.rxRTO = int32(KCP_RTO_DEF) 70 | kcp.rxMinRTO = int32(KCP_RTO_MIN) 71 | kcp.interval = KCP_INTERVAL 72 | kcp.tsFlush = KCP_INTERVAL 73 | kcp.ssthresh = KCP_THRESH_INIT 74 | kcp.fastACKLimit = KCP_FASTACK_LIMIT 75 | kcp.deadLink = KCP_DEADLINK 76 | 77 | return kcp 78 | } 79 | 80 | func (kcp *KCP) SetOutput(outputCallback OutputCallback) { 81 | if outputCallback != nil { 82 | kcp.outputCallback = outputCallback 83 | } 84 | } 85 | 86 | // calculate a message data size 87 | func (kcp *KCP) PeekSize() (size int) { 88 | if len(kcp.recvQueue) <= 0 { 89 | return 0 90 | } 91 | 92 | seg := kcp.recvQueue[0] 93 | if seg.frg == 0 { 94 | return len(seg.dataBuffer) 95 | } 96 | 97 | if len(kcp.recvQueue) < int(seg.frg+1) { 98 | return 0 99 | } 100 | 101 | for idx := range kcp.recvQueue { 102 | seg := kcp.recvQueue[idx] 103 | size += len(seg.dataBuffer) 104 | if seg.frg == 0 { 105 | break 106 | } 107 | } 108 | 109 | return 110 | } 111 | 112 | // read a whole message packet 113 | // User or upper level recv: returns size, returns below zero for EAGAIN 114 | func (kcp *KCP) Recv(buffer []byte) (int, error) { 115 | if len(kcp.recvQueue) == 0 { 116 | return 0, ErrNoReadableData 117 | } 118 | 119 | peekSize := kcp.PeekSize() 120 | if peekSize <= 0 { 121 | return 0, ErrNoReadableData 122 | } 123 | 124 | if peekSize > len(buffer) { 125 | return 0, ErrNoEnoughSpace 126 | } 127 | 128 | isFastRecover := false 129 | if len(kcp.recvQueue) >= int(kcp.recvWnd) { 130 | isFastRecover = true 131 | } 132 | 133 | // merge fragment 134 | n := 0 135 | count := 0 136 | for idx := range kcp.recvQueue { 137 | seg := kcp.recvQueue[idx] 138 | frg := seg.frg 139 | copy(buffer[n:], seg.dataBuffer) 140 | n += len(seg.dataBuffer) 141 | count++ 142 | 143 | putSegment(seg) 144 | if frg == 0 { 145 | break 146 | } 147 | } 148 | 149 | if count > 0 { 150 | kcp.recvQueue = removeFront(kcp.recvQueue, count) 151 | } 152 | 153 | // move seg from recvBuffer to recvQueue 154 | count = 0 155 | for idx := range kcp.recvBuffer { 156 | seg := kcp.recvBuffer[idx] 157 | if seg.sn == kcp.recvNext && len(kcp.recvQueue)+count < int(kcp.recvWnd) { 158 | kcp.recvQueue = append(kcp.recvQueue, seg) 159 | kcp.recvNext++ 160 | count++ 161 | } else { 162 | break 163 | } 164 | } 165 | 166 | if count > 0 { 167 | kcp.recvBuffer = removeFront(kcp.recvBuffer, count) 168 | } 169 | 170 | // tell remote my recv window size, need to send KCP_CMD_WINS 171 | if (len(kcp.recvQueue) < int(kcp.recvWnd)) && isFastRecover { 172 | // ready to send back IKCP_CMD_WINS in ikcp_flush 173 | // tell remote my window size in next 'flush' 174 | kcp.probe |= KCP_ASK_TELL 175 | } 176 | 177 | return n, nil 178 | } 179 | 180 | func (kcp *KCP) Send(buffer []byte) error { 181 | // append to previous segment in streaming mode (if possible) 182 | if kcp.streamMode { 183 | if len(kcp.sendQueue) > 0 { 184 | seg := kcp.sendQueue[len(kcp.sendQueue)-1] 185 | if len(seg.dataBuffer) < int(kcp.mss) { 186 | capacity := int(kcp.mss) - len(seg.dataBuffer) 187 | extend := 0 188 | if len(buffer) < capacity { 189 | extend = len(buffer) 190 | } else { 191 | extend = capacity 192 | } 193 | 194 | // copy data to old segment 195 | orgLen := len(seg.dataBuffer) 196 | seg.dataBuffer = seg.dataBuffer[:orgLen+extend] 197 | copy(seg.dataBuffer[orgLen:], buffer) 198 | buffer = buffer[extend:] 199 | } 200 | } 201 | 202 | if len(buffer) == 0 { 203 | return nil 204 | } 205 | } 206 | 207 | count := 0 208 | if len(buffer) <= (int)(kcp.mss) { 209 | count = 1 210 | } else { 211 | count = (len(buffer) + int(kcp.mss) - 1) / int(kcp.mss) 212 | } 213 | 214 | if count >= int(KCP_WND_RCV) { 215 | return ErrDataTooLong 216 | } 217 | 218 | if count == 0 { 219 | count = 1 220 | } 221 | 222 | // slice data to fregment 223 | for i := 0; i < count; i++ { 224 | size := len(buffer) 225 | if size > int(kcp.mss) { 226 | size = int(kcp.mss) 227 | } 228 | 229 | seg := getSegment(kcp.mss) 230 | seg.dataBuffer = seg.dataBuffer[:size] 231 | copy(seg.dataBuffer, buffer[:size]) 232 | if kcp.streamMode { 233 | seg.frg = 0 234 | } else { 235 | seg.frg = uint32(count - i - 1) 236 | } 237 | 238 | kcp.sendQueue = append(kcp.sendQueue, seg) 239 | buffer = buffer[size:] 240 | } 241 | 242 | return nil 243 | } 244 | 245 | func (kcp *KCP) updateACK(rtt int32) int32 { 246 | if kcp.stableNetwork { 247 | return kcp.updateACK2(rtt) 248 | } 249 | 250 | return kcp.updateACK1(rtt) 251 | } 252 | 253 | // calculate RTO 254 | // RFC6298:http://tools.ietf.org/html/rfc6298 255 | func (kcp *KCP) updateACK1(rtt int32) int32 { 256 | if kcp.rxSRTT == 0 { 257 | kcp.rxSRTT = rtt 258 | kcp.rxRTTValue = rtt >> 1 // 1/2 259 | } else { 260 | delta := rtt - kcp.rxSRTT 261 | if delta < 0 { 262 | delta = -delta 263 | } 264 | 265 | kcp.rxRTTValue = (3*kcp.rxRTTValue + delta) / 4 // 1/4 266 | kcp.rxSRTT = (7*kcp.rxSRTT + rtt) / 8 // 1/8 267 | if kcp.rxSRTT < 1 { 268 | kcp.rxSRTT = 1 269 | } 270 | } 271 | 272 | rto := kcp.rxSRTT + int32(max(kcp.interval, uint32(4*kcp.rxRTTValue))) 273 | kcp.rxRTO = int32(bound(uint32(kcp.rxMinRTO), uint32(rto), KCP_RTO_MAX)) 274 | return kcp.rxRTO 275 | } 276 | 277 | // calculate RTO 278 | // updateACK2 port from tcp_input.c 'tcp_rtt_estimator' function 279 | // https://github.com/torvalds/linux/blob/master/net/ipv4/tcp_input.c 280 | func (kcp *KCP) updateACK2(rtt int32) int32 { 281 | srtt := kcp.rxSRTT 282 | m := rtt 283 | if kcp.rxSRTT == 0 { 284 | srtt = m << 3 285 | kcp.mdev = m << 1 // make sure rto = 3*rtt 286 | kcp.rxRTTValue = int32(max(uint32(kcp.mdev), KCP_RTO_MIN)) 287 | kcp.mdevMax = kcp.rxRTTValue 288 | kcp.rttSN = int32(kcp.sendNext) 289 | } else { 290 | m -= srtt >> 3 291 | srtt += m // rtt = 7/8 rtt + 1/8 new 292 | if m < 0 { 293 | m = -m // abs 294 | m -= (kcp.mdev >> 2) 295 | if m > 0 { 296 | m >>= 3 297 | } 298 | } else { 299 | m -= (kcp.mdev >> 2) 300 | } 301 | 302 | kcp.mdev += m // mdev = 3/4 mdev + 1/4 new 303 | if kcp.mdev > kcp.mdevMax { 304 | kcp.mdevMax = kcp.mdev 305 | if kcp.mdevMax > kcp.rxRTTValue { 306 | kcp.rxRTTValue = kcp.mdevMax 307 | } 308 | 309 | if int32(kcp.sendUNA) > kcp.rttSN { 310 | if kcp.mdevMax < kcp.rxRTTValue { 311 | kcp.rxRTTValue -= (kcp.rxRTTValue - kcp.mdevMax) >> 2 312 | } 313 | 314 | kcp.rttSN = int32(kcp.sendNext) 315 | kcp.mdevMax = int32(KCP_RTO_MIN) 316 | } 317 | } 318 | } 319 | 320 | kcp.rxSRTT = int32(max(1, uint32(srtt))) 321 | //rto := kcp.rxSRTT*1 + 4*kcp.mdev 322 | rto := rtt + 4*kcp.mdev 323 | kcp.rxRTO = int32(bound(uint32(kcp.rxMinRTO), uint32(rto), KCP_RTO_MAX)) 324 | return kcp.rxRTO 325 | } 326 | 327 | func (kcp *KCP) setSendUNA() { 328 | if len(kcp.sendBuffer) > 0 { 329 | seg := kcp.sendBuffer[0] 330 | kcp.sendUNA = seg.sn 331 | } else { 332 | kcp.sendUNA = kcp.sendNext 333 | } 334 | } 335 | 336 | func (kcp *KCP) parseACK(sn uint32) { 337 | if timediff(sn, kcp.sendUNA) < 0 || timediff(sn, kcp.sendNext) >= 0 { 338 | return 339 | } 340 | 341 | for idx := range kcp.sendBuffer { 342 | seg := kcp.sendBuffer[idx] 343 | if sn == seg.sn { 344 | seg.acked = true 345 | break 346 | } 347 | 348 | if timediff(sn, seg.sn) < 0 { 349 | break 350 | } 351 | } 352 | } 353 | 354 | func (kcp *KCP) parseUNA(una uint32) { 355 | count := 0 356 | for idx := range kcp.sendBuffer { 357 | seg := kcp.sendBuffer[idx] 358 | if timediff(una, seg.sn) > 0 { 359 | putSegment(seg) 360 | count++ 361 | } else { 362 | break 363 | } 364 | } 365 | 366 | if count > 0 { 367 | kcp.sendBuffer = removeFront(kcp.sendBuffer, count) 368 | } 369 | } 370 | 371 | func (kcp *KCP) parseFastACK(sn uint32, ts uint32) { 372 | if timediff(sn, kcp.sendUNA) < 0 || timediff(sn, kcp.sendNext) >= 0 { 373 | return 374 | } 375 | 376 | for idx := range kcp.sendBuffer { 377 | seg := kcp.sendBuffer[idx] 378 | if timediff(sn, seg.sn) < 0 { 379 | break 380 | } else if sn != seg.sn { 381 | if timediff(ts, seg.ts) >= 0 { 382 | seg.fastACK++ 383 | } 384 | } 385 | } 386 | } 387 | 388 | func (kcp *KCP) pushACK(sn, ts uint32) { 389 | kcp.ackList = append(kcp.ackList, packACK(sn, ts)) 390 | } 391 | 392 | // Return true if this message has been received 393 | func (kcp *KCP) parseData(newseg *segment) bool { 394 | repeat := false 395 | sn := newseg.sn 396 | if timediff(sn, kcp.recvNext+kcp.recvWnd) >= 0 || timediff(sn, kcp.recvNext) < 0 { 397 | return true 398 | } 399 | 400 | istIdx := 0 401 | for idx := len(kcp.recvBuffer) - 1; idx >= 0; idx-- { 402 | seg := kcp.recvBuffer[idx] 403 | if seg.sn == sn { 404 | // repeat message package 405 | repeat = true 406 | break 407 | } 408 | 409 | if timediff(sn, seg.sn) > 0 { 410 | istIdx = idx + 1 411 | break 412 | } 413 | } 414 | 415 | if !repeat { 416 | if istIdx == len(kcp.recvBuffer) { 417 | kcp.recvBuffer = append(kcp.recvBuffer, newseg) 418 | } else { 419 | kcp.recvBuffer = append(kcp.recvBuffer, &segment{}) 420 | copy(kcp.recvBuffer[istIdx+1:], kcp.recvBuffer[istIdx:]) 421 | kcp.recvBuffer[istIdx] = newseg 422 | } 423 | } 424 | 425 | // move available data from recvBuffer -> recvQueue 426 | count := 0 427 | for idx := range kcp.recvBuffer { 428 | seg := kcp.recvBuffer[idx] 429 | if seg.sn == kcp.recvNext && len(kcp.recvQueue) < int(kcp.recvWnd) { 430 | count++ 431 | kcp.recvNext++ 432 | } else { 433 | break 434 | } 435 | } 436 | 437 | if count > 0 { 438 | kcp.recvQueue = append(kcp.recvQueue, kcp.recvBuffer[:count]...) 439 | kcp.recvBuffer = removeFront(kcp.recvBuffer, count) 440 | } 441 | return repeat 442 | } 443 | 444 | func (kcp *KCP) Input(data []byte) error { 445 | prevUNA := kcp.sendUNA 446 | var maxACK, latestACKTime uint32 = 0, 0 447 | flag := 0 448 | 449 | if len(data) < int(KCP_OVERHEAD) { 450 | return ErrDataInvalid 451 | } 452 | 453 | currentTime := SetupFromNowMS() 454 | for { 455 | var ts, sn, length, una, convID uint32 456 | var wnd uint16 457 | var cmd, frg uint8 458 | if len(data) < int(KCP_OVERHEAD) { 459 | break 460 | } 461 | 462 | data = decode32u(data, &convID) 463 | if convID != kcp.convID { 464 | return ErrDifferenceConvID 465 | } 466 | 467 | data = decode8u(data, &cmd) 468 | data = decode8u(data, &frg) 469 | data = decode16u(data, &wnd) 470 | data = decode32u(data, &ts) 471 | data = decode32u(data, &sn) 472 | data = decode32u(data, &una) 473 | data = decode32u(data, &length) 474 | 475 | if len(data) < int(length) || length < 0 { 476 | return ErrDataInvalid 477 | } 478 | 479 | if uint32(cmd) != KCP_CMD_PUSH && uint32(cmd) != KCP_CMD_ACK && 480 | uint32(cmd) != KCP_CMD_WASK && uint32(cmd) != KCP_CMD_WINS { 481 | return ErrDataInvalid 482 | } 483 | 484 | kcp.remoteWnd = uint32(wnd) 485 | kcp.parseUNA(una) 486 | kcp.setSendUNA() 487 | switch uint32(cmd) { 488 | case KCP_CMD_ACK: 489 | if timediff(currentTime, ts) >= 0 { 490 | _ = kcp.updateACK(timediff(currentTime, ts)) 491 | } 492 | kcp.parseACK(sn) 493 | kcp.setSendUNA() 494 | 495 | if flag == 0 { 496 | flag = 1 497 | maxACK = sn 498 | latestACKTime = ts 499 | } else { 500 | if timediff(sn, maxACK) > 0 { 501 | maxACK = sn 502 | latestACKTime = ts 503 | } 504 | } 505 | case KCP_CMD_PUSH: 506 | if timediff(sn, kcp.recvNext+kcp.recvWnd) < 0 { 507 | kcp.pushACK(sn, ts) 508 | if timediff(sn, kcp.recvNext) >= 0 { 509 | seg := getSegment(kcp.mss) 510 | seg.dataBuffer = seg.dataBuffer[:length] 511 | seg.convID = convID 512 | seg.cmd = uint32(cmd) 513 | seg.frg = uint32(frg) 514 | seg.wnd = uint32(wnd) 515 | seg.ts = ts 516 | seg.sn = sn 517 | seg.una = una 518 | repeat := kcp.parseData(seg) 519 | if !repeat { 520 | // delay copy 521 | if length > 0 { 522 | copy(seg.dataBuffer, data[:length]) 523 | } 524 | } else { 525 | // repeat packet, throw it away 526 | putSegment(seg) 527 | } 528 | } 529 | } 530 | case KCP_CMD_WASK: 531 | // ready to send back IKCP_CMD_WINS in ikcp_flush 532 | // tell remote my window size 533 | kcp.probe |= KCP_ASK_TELL 534 | case KCP_CMD_WINS: 535 | // do nothing 536 | default: 537 | return ErrDataInvalid 538 | } 539 | 540 | data = data[length:] 541 | } 542 | 543 | if flag != 0 { 544 | kcp.parseFastACK(maxACK, latestACKTime) 545 | } 546 | 547 | // update local cwnd 548 | if timediff(kcp.sendUNA, prevUNA) > 0 { 549 | if kcp.cwnd < kcp.remoteWnd { 550 | mss := kcp.mss 551 | if kcp.cwnd < kcp.ssthresh { 552 | kcp.cwnd++ 553 | kcp.incr += mss 554 | } else { 555 | if kcp.incr < mss { 556 | kcp.incr = mss 557 | } 558 | 559 | // like tcp 560 | kcp.incr += (mss*mss)/kcp.incr + (mss / 16) 561 | if (kcp.cwnd+1)*mss <= kcp.incr { 562 | var tmpVar uint32 = 1 563 | if mss > 0 { 564 | tmpVar = mss 565 | } 566 | kcp.cwnd = (kcp.incr + mss - 1) / tmpVar 567 | } 568 | } 569 | 570 | if kcp.cwnd > kcp.remoteWnd { 571 | kcp.cwnd = kcp.remoteWnd 572 | kcp.incr = kcp.remoteWnd * mss 573 | } 574 | } 575 | } 576 | 577 | return nil 578 | } 579 | 580 | func (kcp *KCP) flush(isClose bool) error { 581 | if kcp.updated == 0 { 582 | return nil 583 | } 584 | 585 | currentTime := SetupFromNowMS() 586 | seg := &segment{} 587 | seg.convID = kcp.convID 588 | seg.cmd = KCP_CMD_ACK 589 | seg.frg = 0 590 | // wnd unused 591 | if uint32(len(kcp.recvQueue)) < kcp.recvWnd { 592 | seg.wnd = kcp.recvWnd - uint32(len(kcp.recvQueue)) 593 | } 594 | seg.una = kcp.recvNext 595 | seg.sn = 0 596 | seg.ts = 0 597 | 598 | if !isClose { 599 | // flush acknowledges 600 | for idx := range kcp.ackList { 601 | if kcp.buffer.RawLen()+int(KCP_OVERHEAD) > int(kcp.mtu) { 602 | err := kcp.outputCallback(kcp.buffer.RawData()) 603 | if err != nil { 604 | return err 605 | } 606 | 607 | kcp.buffer.Reset() 608 | } 609 | 610 | seg.sn, seg.ts = unpackACK(kcp.ackList[idx]) 611 | kcp.buffer.WriteOverHeader(seg) 612 | } 613 | } 614 | kcp.ackList = kcp.ackList[:0] 615 | 616 | // probe window size (if remote window size equals zero) 617 | if kcp.remoteWnd == 0 { 618 | if kcp.probeWait == 0 { 619 | kcp.probeWait = KCP_PROBE_INIT 620 | kcp.tsProbe = currentTime + kcp.probeWait 621 | } else { 622 | if timediff(currentTime, kcp.probeWait) >= 0 { 623 | if kcp.probeWait < KCP_PROBE_INIT { 624 | kcp.probeWait = KCP_PROBE_INIT 625 | } 626 | kcp.probeWait += kcp.probeWait / 2 627 | 628 | if kcp.probeWait > KCP_PROBE_LIMIT { 629 | kcp.probeWait = KCP_PROBE_LIMIT 630 | } 631 | kcp.tsProbe = currentTime + kcp.probeWait 632 | kcp.probe |= KCP_ASK_SEND 633 | } 634 | } 635 | } else { 636 | kcp.tsProbe = 0 637 | kcp.probeWait = 0 638 | } 639 | 640 | if !isClose { 641 | // flush window probing commands 642 | if (kcp.probe & KCP_ASK_SEND) != 0 { 643 | seg.cmd = KCP_CMD_WASK 644 | if kcp.buffer.RawLen()+int(KCP_OVERHEAD) > int(kcp.mtu) { 645 | err := kcp.outputCallback(kcp.buffer.RawData()) 646 | if err != nil { 647 | return err 648 | } 649 | kcp.buffer.Reset() 650 | } 651 | 652 | kcp.buffer.WriteOverHeader(seg) 653 | } 654 | 655 | if (kcp.probe & KCP_ASK_TELL) != 0 { 656 | seg.cmd = KCP_CMD_WINS 657 | if kcp.buffer.RawLen()+int(KCP_OVERHEAD) > int(kcp.mtu) { 658 | err := kcp.outputCallback(kcp.buffer.RawData()) 659 | if err != nil { 660 | return err 661 | } 662 | kcp.buffer.Reset() 663 | } 664 | 665 | kcp.buffer.WriteOverHeader(seg) 666 | } 667 | kcp.probe = 0 668 | } 669 | 670 | // calculate window size 671 | cwnd := min(kcp.sendWnd, kcp.remoteWnd) 672 | if !kcp.nocwnd { 673 | cwnd = min(kcp.cwnd, cwnd) 674 | } 675 | 676 | // move data from sendQueue to sendBuffer 677 | count := 0 678 | for idx := 0; idx < len(kcp.sendQueue); idx++ { 679 | // flow control 680 | // too many package are not ACKed maybe the net is crowd, so send this message next time 681 | if timediff(kcp.sendNext, kcp.sendUNA+cwnd) >= 0 { 682 | break 683 | } 684 | 685 | newseg := kcp.sendQueue[idx] 686 | newseg.convID = kcp.convID 687 | newseg.cmd = KCP_CMD_PUSH 688 | newseg.wnd = seg.wnd 689 | newseg.ts = currentTime 690 | newseg.sn = kcp.sendNext 691 | newseg.una = kcp.recvNext 692 | newseg.resendTs = currentTime 693 | newseg.rto = uint32(kcp.rxRTO) 694 | newseg.fastACK = 0 695 | newseg.xmit = 0 696 | kcp.sendBuffer = append(kcp.sendBuffer, newseg) 697 | kcp.sendNext++ 698 | count++ 699 | } 700 | if count > 0 { 701 | kcp.sendQueue = removeFront(kcp.sendQueue, count) 702 | } 703 | 704 | // calculate resent 705 | var resent uint32 706 | if kcp.fastResendACK > 0 { 707 | resent = kcp.fastResendACK 708 | } else { 709 | resent = 0xFFFFFFFF 710 | } 711 | 712 | var minRTO uint32 713 | if !kcp.noDelay { 714 | minRTO = uint32(kcp.rxRTO >> 3) 715 | } else { 716 | minRTO = 0 717 | } 718 | 719 | // flush data segments 720 | lost := false 721 | change := 0 722 | for idx := 0; idx < len(kcp.sendBuffer); idx++ { 723 | sendSegment := kcp.sendBuffer[idx] 724 | needSend := false 725 | if sendSegment.acked { 726 | continue 727 | } 728 | 729 | // first send 730 | if sendSegment.xmit == 0 { 731 | needSend = true 732 | sendSegment.xmit++ 733 | sendSegment.rto = uint32(kcp.rxRTO) 734 | sendSegment.resendTs = currentTime + sendSegment.rto + minRTO 735 | } else if timediff(currentTime, sendSegment.resendTs) >= 0 { 736 | needSend = true 737 | sendSegment.xmit++ 738 | kcp.xmit++ 739 | if !kcp.noDelay { 740 | sendSegment.rto += uint32(kcp.rxRTO) 741 | } else { 742 | sendSegment.rto += uint32(kcp.rxRTO / 2) 743 | } 744 | sendSegment.resendTs = currentTime + sendSegment.rto 745 | lost = true 746 | } else if sendSegment.fastACK >= resent { 747 | if sendSegment.xmit <= kcp.fastACKLimit || kcp.fastACKLimit <= 0 { 748 | needSend = true 749 | sendSegment.xmit++ 750 | sendSegment.fastACK = 0 751 | sendSegment.resendTs = currentTime + sendSegment.rto 752 | change++ 753 | } 754 | } 755 | 756 | if needSend { 757 | sendSegment.ts = currentTime 758 | sendSegment.wnd = seg.wnd 759 | sendSegment.una = kcp.recvNext 760 | 761 | if kcp.buffer.RawLen()+int(KCP_OVERHEAD)+len(sendSegment.dataBuffer) > int(kcp.mtu) { 762 | err := kcp.outputCallback(kcp.buffer.RawData()) 763 | if err != nil { 764 | return err 765 | } 766 | kcp.buffer.Reset() 767 | } 768 | 769 | kcp.buffer.WriteOverHeader(sendSegment) 770 | if len(sendSegment.dataBuffer) > 0 { 771 | kcp.buffer.Write(sendSegment.dataBuffer) 772 | } 773 | 774 | if sendSegment.xmit >= kcp.deadLink { 775 | kcp.state = 0xFFFFFFFF 776 | } 777 | } 778 | } 779 | 780 | // flash remain segments 781 | if kcp.buffer.Len() > 0 { 782 | err := kcp.outputCallback(kcp.buffer.RawData()) 783 | if err != nil { 784 | return err 785 | } 786 | kcp.buffer.Reset() 787 | } 788 | 789 | // update ssthresh 790 | // rate halving, https://tools.ietf.org/html/rfc6937 791 | if change > 0 { 792 | inflight := kcp.sendNext - kcp.sendUNA 793 | kcp.ssthresh = inflight / 2 794 | if kcp.ssthresh < KCP_THRESH_MIN { 795 | kcp.ssthresh = KCP_THRESH_MIN 796 | } 797 | kcp.cwnd = kcp.ssthresh + resent 798 | kcp.incr = kcp.cwnd * kcp.mss 799 | } 800 | 801 | // if some package lost 802 | if lost { 803 | kcp.ssthresh = cwnd / 2 804 | if kcp.ssthresh < KCP_THRESH_MIN { 805 | kcp.ssthresh = KCP_THRESH_MIN 806 | } 807 | 808 | kcp.cwnd = 1 809 | kcp.incr = kcp.mss 810 | } 811 | 812 | if kcp.cwnd < 1 { 813 | kcp.cwnd = 1 814 | kcp.incr = kcp.mss 815 | } 816 | 817 | return nil 818 | } 819 | 820 | //--------------------------------------------------------------------- 821 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 822 | // 'Check' when to call it again (without Input/Send calling). 823 | //--------------------------------------------------------------------- 824 | func (kcp *KCP) Update() error { 825 | currentTime := SetupFromNowMS() 826 | if kcp.updated == 0 { 827 | kcp.updated = 1 828 | kcp.tsFlush = currentTime 829 | } 830 | 831 | slap := timediff(currentTime, kcp.tsFlush) 832 | if slap >= 10000 || slap < -10000 { 833 | kcp.tsFlush = currentTime 834 | slap = 0 835 | } 836 | 837 | if slap >= 0 { 838 | kcp.tsFlush += kcp.interval 839 | if timediff(currentTime, kcp.tsFlush) >= 0 { 840 | kcp.tsFlush = currentTime + kcp.interval 841 | } 842 | 843 | return kcp.flush(false) 844 | } 845 | 846 | return nil 847 | } 848 | 849 | func (kcp *KCP) SetBufferReserved(reserved int) bool { 850 | if reserved < 0 || reserved >= int(kcp.mtu-KCP_OVERHEAD) { 851 | return false 852 | } 853 | 854 | kcp.mss = kcp.mtu - KCP_OVERHEAD - uint32(reserved) 855 | kcp.buffer = nil 856 | kcp.buffer = NewBuffer(int(kcp.mtu), reserved) 857 | return true 858 | } 859 | 860 | func (kcp *KCP) SetMTU(mtu int) bool { 861 | if mtu < 50 || mtu < int(KCP_OVERHEAD) { 862 | return false 863 | } 864 | 865 | kcp.mtu = uint32(mtu) 866 | return true 867 | } 868 | 869 | func (kcp *KCP) SetInterval(interval int) { 870 | if interval > 5000 { 871 | interval = 5000 872 | } else if interval < 5 { 873 | interval = 5 874 | } 875 | 876 | kcp.interval = uint32(interval) 877 | } 878 | 879 | //--------------------------------------------------------------------- 880 | // Determine when should you invoke Update: 881 | // returns when you should invoke Update in millisec, if there 882 | // is no Input/Send calling. you can call Update in that 883 | // time, instead of call update repeatly. 884 | 885 | // Important to reduce unnacessary Update invoking. use it to 886 | // schedule Update (eg. implementing an epoll-like mechanism, 887 | // or optimize Update when handling massive kcp connections) 888 | // wiki: https://github.com/skywind3000/kcp/wiki/KCP-Best-Practice 889 | //--------------------------------------------------------------------- 890 | func (kcp *KCP) Check() uint32 { 891 | currentTime := SetupFromNowMS() 892 | if kcp.updated == 0 { 893 | return currentTime 894 | } 895 | 896 | tsFlush := kcp.tsFlush 897 | if timediff(currentTime, tsFlush) >= 10000 || timediff(currentTime, tsFlush) < -10000 { 898 | tsFlush = currentTime 899 | } 900 | 901 | if timediff(currentTime, tsFlush) >= 0 { 902 | return currentTime 903 | } 904 | 905 | tmPacket := 0x7FFFFFFF 906 | tmFlush := 0x7FFFFFFF 907 | minimal := 0 908 | tsFlush = uint32(timediff(tsFlush, currentTime)) 909 | for idx := range kcp.sendBuffer { 910 | seg := kcp.sendBuffer[idx] 911 | diff := timediff(seg.resendTs, currentTime) 912 | if diff <= 0 { 913 | return currentTime 914 | } 915 | if int(diff) < tmPacket { 916 | tmPacket = int(diff) 917 | } 918 | } 919 | 920 | if tmPacket < tmFlush { 921 | minimal = tmPacket 922 | } else { 923 | minimal = tmFlush 924 | } 925 | 926 | if minimal >= int(kcp.interval) { 927 | minimal = int(kcp.interval) 928 | } 929 | 930 | return currentTime + uint32(minimal) 931 | } 932 | 933 | func (kcp *KCP) SetNoDelay(noDelay bool, interval, resend int, nc bool) { 934 | kcp.noDelay = noDelay 935 | if kcp.noDelay { 936 | kcp.rxMinRTO = int32(KCP_RTO_NDL) 937 | } else { 938 | kcp.rxMinRTO = int32(KCP_RTO_MIN) 939 | } 940 | 941 | kcp.SetInterval(interval) 942 | kcp.fastResendACK = uint32(resend) 943 | kcp.nocwnd = nc 944 | } 945 | 946 | func (kcp *KCP) SetWndSize(sendWnd, recvWnd int) { 947 | kcp.sendWnd = uint32(sendWnd) 948 | kcp.recvWnd = max(uint32(recvWnd), KCP_WND_RCV) 949 | } 950 | 951 | func (kcp *KCP) SendWnd() uint32 { 952 | return kcp.sendWnd 953 | } 954 | 955 | func (kcp *KCP) RemoteWnd() uint32 { 956 | return kcp.remoteWnd 957 | } 958 | 959 | func (kcp *KCP) WaitSend() int { 960 | return len(kcp.sendQueue) + len(kcp.sendBuffer) 961 | } 962 | 963 | func (kcp *KCP) MTU() uint32 { 964 | return kcp.mtu 965 | } 966 | 967 | func (kcp *KCP) MSS() uint32 { 968 | return kcp.mss 969 | } 970 | 971 | func (kcp *KCP) SetStreamMode(streamMode bool) { 972 | kcp.streamMode = streamMode 973 | } 974 | 975 | func (kcp *KCP) IsStreamMode() bool { 976 | return kcp.streamMode 977 | } 978 | 979 | func (kcp *KCP) FlushWhenClosed() { 980 | kcp.flush(true) 981 | } 982 | 983 | func (kcp *KCP) ConvID() uint32 { 984 | return kcp.convID 985 | } 986 | 987 | func (kcp *KCP) RTO() int32 { 988 | return kcp.rxRTO 989 | } 990 | 991 | type KCPStatus struct { 992 | SendUNA int 993 | SendNext int 994 | RecvNext int 995 | LastACK int 996 | Threshold int 997 | RTO int 998 | FastResendACK int 999 | FastACKLimit int 1000 | SendWnd int 1001 | RecvWnd int 1002 | RemoteWnd int 1003 | Wnd int 1004 | SendQueueLen int 1005 | SendBufferLen int 1006 | RecvQueueLen int 1007 | RecvBufferLen int 1008 | ACKListLen int 1009 | Incr int 1010 | } 1011 | 1012 | func (kcp *KCP) Snapshot(status *KCPStatus) { 1013 | if status == nil { 1014 | return 1015 | } 1016 | 1017 | status.SendUNA = int(kcp.sendUNA) 1018 | status.SendNext = int(kcp.sendNext) 1019 | status.RecvNext = int(kcp.recvNext) 1020 | status.LastACK = int(kcp.lastACK) 1021 | status.Threshold = int(kcp.ssthresh) 1022 | status.RTO = int(kcp.rxRTO) 1023 | status.FastResendACK = int(kcp.fastResendACK) 1024 | status.FastACKLimit = int(kcp.fastACKLimit) 1025 | status.SendWnd = int(kcp.sendWnd) 1026 | status.RecvWnd = int(kcp.recvWnd) 1027 | status.RemoteWnd = int(kcp.remoteWnd) 1028 | status.Wnd = int(kcp.cwnd) 1029 | status.SendQueueLen = len(kcp.sendQueue) 1030 | status.SendBufferLen = len(kcp.sendBuffer) 1031 | status.RecvQueueLen = len(kcp.recvQueue) 1032 | status.RecvBufferLen = len(kcp.recvBuffer) 1033 | status.ACKListLen = len(kcp.ackList) 1034 | status.Incr = int(kcp.incr) 1035 | } 1036 | -------------------------------------------------------------------------------- /kcp_buffer.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import ( 4 | "encoding/binary" 5 | ) 6 | 7 | type Buffer struct { 8 | srcBuffer []byte 9 | buffer []byte 10 | segBuffer []byte 11 | reserved int 12 | } 13 | 14 | func NewBuffer(size int, reserved int) *Buffer { 15 | b := &Buffer{ 16 | buffer: make([]byte, size), 17 | segBuffer: make([]byte, KCP_OVERHEAD), 18 | } 19 | 20 | b.reserved = reserved 21 | b.srcBuffer = b.buffer 22 | b.buffer = b.buffer[reserved:] 23 | b.buffer = b.buffer[:0] 24 | return b 25 | } 26 | 27 | func (b *Buffer) Reset() { 28 | b.buffer = b.buffer[:0] 29 | } 30 | 31 | func (b *Buffer) Write(p []byte) { 32 | b.buffer = append(b.buffer, p...) 33 | } 34 | 35 | func (b *Buffer) WriteOverHeader(seg *segment) { 36 | binary.LittleEndian.PutUint32(b.segBuffer, seg.convID) 37 | b.segBuffer[4] = byte(seg.cmd) 38 | b.segBuffer[5] = byte(seg.frg) 39 | binary.LittleEndian.PutUint16(b.segBuffer[6:], uint16(seg.wnd)) 40 | binary.LittleEndian.PutUint32(b.segBuffer[8:], seg.ts) 41 | binary.LittleEndian.PutUint32(b.segBuffer[12:], seg.sn) 42 | binary.LittleEndian.PutUint32(b.segBuffer[16:], seg.una) 43 | binary.LittleEndian.PutUint32(b.segBuffer[20:], uint32(len(seg.dataBuffer))) 44 | b.segBuffer = b.segBuffer[0:] 45 | b.Write(b.segBuffer) 46 | } 47 | 48 | func (b *Buffer) CompareDiff(size int) bool { 49 | return len(b.buffer) > size 50 | } 51 | 52 | func (b *Buffer) Data() []byte { 53 | return b.buffer 54 | } 55 | 56 | func (b *Buffer) RawData() []byte { 57 | return b.srcBuffer[:len(b.buffer)+b.reserved] 58 | } 59 | 60 | func (b *Buffer) Len() int { 61 | return len(b.buffer) 62 | } 63 | 64 | func (b *Buffer) RawLen() int { 65 | return len(b.buffer) + b.reserved 66 | } 67 | -------------------------------------------------------------------------------- /kcp_test.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import ( 4 | "container/list" 5 | "encoding/binary" 6 | "math/rand" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | type DelayPacket struct { 12 | data []byte 13 | Ts uint32 14 | } 15 | 16 | func NewDelayPacket(data []byte) *DelayPacket { 17 | dp := &DelayPacket{ 18 | data: nil, 19 | Ts: 0, 20 | } 21 | 22 | dp.data = make([]byte, len(data)) 23 | copy(dp.data, data) 24 | return dp 25 | } 26 | 27 | type Random struct { 28 | seeds []int 29 | size int 30 | } 31 | 32 | func (r *Random) Rand() int { 33 | if len(r.seeds) == 0 { 34 | return 0 35 | } 36 | 37 | if r.size == 0 { 38 | for i := 0; i < len(r.seeds); i++ { 39 | r.seeds[i] = i 40 | } 41 | 42 | r.size = len(r.seeds) 43 | } 44 | 45 | v := rand.Int() % r.size 46 | x := r.seeds[v] 47 | r.size -= 1 48 | r.seeds[v] = r.seeds[r.size] 49 | return x 50 | } 51 | 52 | func NewRandom(size int) *Random { 53 | r := &Random{} 54 | r.seeds = make([]int, size) 55 | return r 56 | } 57 | 58 | func TestRandom(t *testing.T) { 59 | rand.Seed(time.Now().UnixNano()) 60 | randomValues := make([]int, 1000) 61 | random := NewRandom(100) 62 | for i := 0; i < 1000; i++ { 63 | randomValues[i] = random.Rand() 64 | } 65 | 66 | t.Logf("randomValues: %v", randomValues) 67 | } 68 | 69 | type LatencySimulator struct { 70 | lostRate int // 丢包率 71 | rttMin int // 最小往返时间 72 | rttMax int // 最大往返时间 73 | max int 74 | rand12 *Random 75 | dt12 *list.List 76 | rand21 *Random 77 | dt21 *list.List 78 | TX1 int 79 | TX2 int 80 | } 81 | 82 | func NewLatencySimulator(lostRate, rttMin, rttMax, max int) *LatencySimulator { 83 | ls := &LatencySimulator{ 84 | lostRate: lostRate / 2, 85 | rttMin: rttMin / 2, 86 | rttMax: rttMax / 2, 87 | max: max, 88 | } 89 | 90 | ls.rand12 = NewRandom(100) 91 | ls.dt12 = list.New() 92 | 93 | ls.rand21 = NewRandom(100) 94 | ls.dt21 = list.New() 95 | return ls 96 | } 97 | 98 | // 发送数据 99 | // peer - 端点0/1,从0发送,从1接收;从1发送从0接收 100 | func (ls *LatencySimulator) Send(peer int, data []byte) { 101 | if peer == 0 { 102 | ls.TX1++ 103 | if ls.rand12.Rand() < ls.lostRate { 104 | return 105 | } 106 | 107 | if ls.dt12.Len() >= ls.max { 108 | return 109 | } 110 | } else { 111 | ls.TX2++ 112 | if ls.rand21.Rand() < ls.lostRate { 113 | return 114 | } 115 | 116 | if ls.dt21.Len() >= ls.max { 117 | return 118 | } 119 | } 120 | 121 | packet := NewDelayPacket(data) 122 | current := CurrentMS() 123 | delay := ls.rttMin 124 | if ls.rttMax > ls.rttMin { 125 | delay += rand.Int() % (ls.rttMax - ls.rttMin) 126 | } 127 | packet.Ts = current + uint32(delay) 128 | if peer == 0 { 129 | ls.dt12.PushBack(packet) 130 | } else { 131 | ls.dt21.PushBack(packet) 132 | } 133 | } 134 | 135 | func (ls *LatencySimulator) Recv(peer int, data []byte, max int) int { 136 | var ele *list.Element 137 | if peer == 0 { 138 | if ls.dt21.Len() == 0 { 139 | return -1 140 | } else { 141 | ele = ls.dt21.Front() 142 | } 143 | } else { 144 | if ls.dt12.Len() == 0 { 145 | return -1 146 | } else { 147 | ele = ls.dt12.Front() 148 | } 149 | } 150 | 151 | packet := ele.Value.(*DelayPacket) 152 | current := CurrentMS() 153 | if current < packet.Ts { 154 | return -2 155 | } 156 | 157 | if max < len(packet.data) { 158 | return -3 159 | } 160 | 161 | if peer == 0 { 162 | ls.dt21.Remove(ele) 163 | } else { 164 | ls.dt12.Remove(ele) 165 | } 166 | 167 | max = len(packet.data) 168 | data = data[:max] 169 | copy(data, packet.data) 170 | return max 171 | } 172 | 173 | var vnet *LatencySimulator 174 | 175 | func testKCP(t *testing.T, mode int, modestr string) { 176 | vnet = NewLatencySimulator(10, 60, 125, 1000) 177 | kcp1 := NewKCP(0x11223344, func(p []byte) { 178 | vnet.Send(0, p) 179 | t.Logf("kcp1 output: %v", p) 180 | }) 181 | 182 | kcp2 := NewKCP(0x11223344, func(p []byte) { 183 | vnet.Send(1, p) 184 | t.Logf("kcp2 output: %v", p) 185 | }) 186 | 187 | current := CurrentMS() 188 | var slap uint32 = current + uint32(20) 189 | var index uint32 190 | var next uint32 191 | var summaryRTT uint32 192 | 193 | count := 0 194 | maxRTT := 0 195 | 196 | kcp1.SetWndSize(128, 128) 197 | kcp2.SetWndSize(128, 128) 198 | 199 | if mode == 0 { 200 | kcp1.SetNoDelay(false, 10, 0, false) 201 | kcp2.SetNoDelay(false, 10, 0, false) 202 | } else if mode == 1 { 203 | kcp1.SetNoDelay(false, 10, 0, true) 204 | kcp2.SetNoDelay(false, 10, 0, true) 205 | } else { 206 | kcp1.SetNoDelay(true, 10, 2, true) 207 | kcp2.SetNoDelay(true, 10, 2, true) 208 | 209 | kcp1.rxMinRTO = 10 210 | kcp1.fastResendACK = 1 211 | } 212 | 213 | kcp1Sended := 0 214 | loops := 0 215 | buffer := make([]byte, 2000) 216 | ts1 := CurrentMS() 217 | for { 218 | loops++ 219 | <-time.After(1 * time.Millisecond) 220 | 221 | current = CurrentMS() 222 | kcp1.Update() 223 | kcp2.Update() 224 | 225 | // 每隔 20ms,kcp1发送数据 226 | for ; current >= slap; slap += 20 { 227 | binary.LittleEndian.PutUint32(buffer[0:4], uint32(index)) 228 | binary.LittleEndian.PutUint32(buffer[4:8], uint32(current)) 229 | kcp1.Send(buffer[0:8]) 230 | index++ 231 | kcp1Sended++ 232 | break 233 | } 234 | t.Logf("kcp1Sended: %v", kcp1Sended) 235 | 236 | // 处理虚拟网络:检测是否有udp包从p1->p2 237 | for { 238 | hr := vnet.Recv(1, buffer, 2000) 239 | if hr < 0 { 240 | break 241 | } 242 | 243 | t.Logf("kcp2 recved,len: %v", hr) 244 | // 如果 p2收到udp,则作为下层协议输入到kcp2 245 | kcp2.Input(buffer[:hr]) 246 | } 247 | 248 | // 处理虚拟网络:检测是否有udp包从p2->p1 249 | for { 250 | hr := vnet.Recv(0, buffer, 2000) 251 | if hr < 0 { 252 | break 253 | } 254 | 255 | t.Logf("kcp1 recved, len: %v", hr) 256 | // 如果 p1收到udp,则作为下层协议输入到kcp1 257 | kcp1.Input(buffer[:hr]) 258 | } 259 | 260 | // kcp2接收到任何包都返回回去 261 | for { 262 | hr, err := kcp2.Recv(buffer) 263 | if err != nil { 264 | break 265 | } 266 | 267 | t.Logf("kcp2.Send: %v", hr) 268 | // 如果收到包就回射 269 | kcp2.Send(buffer[:hr]) 270 | } 271 | 272 | // kcp1收到kcp2的回射数据 273 | for { 274 | hr, err := kcp1.Recv(buffer) 275 | if err != nil { 276 | break 277 | } 278 | t.Logf("kcp1 recved: %v", hr) 279 | 280 | sn := binary.LittleEndian.Uint32(buffer[0:4]) 281 | ts := binary.LittleEndian.Uint32(buffer[4:8]) 282 | rtt := current - ts 283 | if sn != next { 284 | // 如果收到的包不连续 285 | t.Logf("ERROR sn %v <-> %v", count, next) 286 | return 287 | } 288 | 289 | next++ 290 | summaryRTT += rtt 291 | count++ 292 | if rtt > uint32(maxRTT) { 293 | maxRTT = int(rtt) 294 | } 295 | t.Logf("[RECV] mode=%v, sn=%v, rtt=%v", mode, sn, rtt) 296 | } 297 | 298 | if next > 1 || loops > 5 { 299 | break 300 | } 301 | } 302 | 303 | ts1 = CurrentMS() - ts1 304 | t.Logf("%s mode result: %vms", modestr, ts1) 305 | t.Logf("avgrtt=%v maxrtt=%v tx=%v", int(summaryRTT)/count, maxRTT, vnet.TX1) 306 | } 307 | 308 | func TestKCP(t *testing.T) { 309 | rand.Seed(time.Now().UnixNano()) 310 | testKCP(t, 0, "default") 311 | //testKCP(t, 1, "normal") 312 | //testKCP(t, 2, "fast") 313 | } 314 | -------------------------------------------------------------------------------- /pool.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import "sync" 4 | 5 | var ( 6 | segmentPool sync.Pool 7 | ) 8 | 9 | // size is MSS 10 | func getSegment(size uint32) *segment { 11 | if segmentPool.New == nil { 12 | segmentPool.New = func() interface{} { 13 | s := &segment{} 14 | s.dataBuffer = make([]byte, int(size)) 15 | s.dataBuffer = s.dataBuffer[:0] 16 | return s 17 | } 18 | } 19 | 20 | return segmentPool.Get().(*segment) 21 | } 22 | 23 | func putSegment(seg *segment) { 24 | seg.reset() 25 | segmentPool.Put(seg) 26 | } 27 | -------------------------------------------------------------------------------- /protocol.go: -------------------------------------------------------------------------------- 1 | package gokcp 2 | 3 | import ( 4 | "time" 5 | _ "unsafe" 6 | ) 7 | 8 | const ( 9 | KCP_RTO_NDL uint32 = 30 // no delay model min rto 10 | KCP_RTO_MIN uint32 = 100 // normal model min rto 11 | KCP_RTO_DEF uint32 = 200 // rto 12 | KCP_RTO_MAX uint32 = 60000 // max rto 13 | KCP_CMD_PUSH uint32 = 81 // cmd: push data to remote 14 | KCP_CMD_ACK uint32 = 82 // cmd: ack 15 | KCP_CMD_WASK uint32 = 83 // cmd: window probe(ask) 16 | KCP_CMD_WINS uint32 = 94 // cmd: window size(tell) 17 | KCP_ASK_SEND uint32 = 1 // need to send KCP_CMD_WASK 18 | KCP_ASK_TELL uint32 = 2 // need to send KCP_CMD_WINS 19 | KCP_WND_SND uint32 = 32 // send window size, uint package not bytes length 20 | KCP_WND_RCV uint32 = 128 // recv windows size, uint package not bytes length 21 | KCP_MTU_DEF uint32 = 1400 // mtu 22 | KCP_ACK_FAST uint32 = 3 23 | KCP_INTERVAL uint32 = 100 // update interval 24 | KCP_OVERHEAD uint32 = 24 // kcp package head size 25 | KCP_DEADLINK uint32 = 20 26 | KCP_THRESH_INIT uint32 = 2 27 | KCP_THRESH_MIN uint32 = 2 28 | KCP_PROBE_INIT uint32 = 5000 // 5 secs to probe window size 29 | KCP_PROBE_LIMIT uint32 = 100000 // up to 100 secs to probe window 30 | KCP_FASTACK_LIMIT uint32 = 5 // max times to trigger fastack 31 | ) 32 | 33 | type OutputCallback func(p []byte) error 34 | 35 | const PackBits = 32 36 | 37 | func unpackACK(ack uint64) (sn, ts uint32) { 38 | const mask = 1<> PackBits) & mask) 40 | ts = uint32(ack & mask) 41 | return 42 | } 43 | 44 | func packACK(sn, ts uint32) uint64 { 45 | const mask = 1< len(p) { 51 | p = p[:0] 52 | } else { 53 | p = p[count:] 54 | } 55 | 56 | return p 57 | } 58 | 59 | //go:linkname nanotime runtime.nanotime 60 | func nanotime() int64 61 | 62 | var kcpStartTime = nanotime() 63 | 64 | func SetupFromNowMS() uint32 { 65 | return uint32((nanotime() - kcpStartTime) / (1000 * 1000)) 66 | } 67 | 68 | func NowMS() int64 { 69 | now := time.Now() 70 | return now.Unix()*1000 + int64(now.Nanosecond()/1e6) 71 | } 72 | --------------------------------------------------------------------------------