package kcp import ( "bytes" "container/list" "encoding/binary" "fmt" "math/rand" "sync" "testing" "time" ) func iclock() int32 { return int32((time.Now().UnixNano() / 1000000) & 0xffffffff) } type DelayPacket struct { _ptr []byte _size int _ts int32 } func (p *DelayPacket) Init(size int, src []byte) { p._ptr = make([]byte, size) p._size = size copy(p._ptr, src[:size]) } func (p *DelayPacket) ptr() []byte { return p._ptr } func (p *DelayPacket) size() int { return p._size } func (p *DelayPacket) ts() int32 { return p._ts } func (p *DelayPacket) setts(ts int32) { p._ts = ts } type DelayTunnel struct{ *list.List } type Random *rand.Rand type LatencySimulator struct { current int32 lostrate, rttmin, rttmax, nmax int p12 DelayTunnel p21 DelayTunnel r12 *rand.Rand r21 *rand.Rand } // lostrate: 往返一周丢包率的百分比,默认 10% // rttmin:rtt最小值,默认 60 // rttmax:rtt最大值,默认 125 //func (p *LatencySimulator)Init(int lostrate = 10, int rttmin = 60, int rttmax = 125, int nmax = 1000): func (p *LatencySimulator) Init(lostrate, rttmin, rttmax, nmax int) { p.r12 = rand.New(rand.NewSource(9)) p.r21 = rand.New(rand.NewSource(99)) p.p12 = DelayTunnel{list.New()} p.p21 = DelayTunnel{list.New()} p.current = iclock() p.lostrate = lostrate / 2 // 上面数据是往返丢包率,单程除以2 p.rttmin = rttmin / 2 p.rttmax = rttmax / 2 p.nmax = nmax } // 发送数据 // peer - 端点0/1,从0发送,从1接收;从1发送从0接收 func (p *LatencySimulator) send(peer int, data []byte, size int) int { rnd := 0 if peer == 0 { rnd = p.r12.Intn(100) } else { rnd = p.r21.Intn(100) } //println("!!!!!!!!!!!!!!!!!!!!", rnd, p.lostrate, peer) if rnd < p.lostrate { return 0 } pkt := &DelayPacket{} pkt.Init(size, data) p.current = iclock() delay := p.rttmin if p.rttmax > p.rttmin { delay += rand.Int() % (p.rttmax - p.rttmin) } pkt.setts(p.current + int32(delay)) if peer == 0 { p.p12.PushBack(pkt) } else { p.p21.PushBack(pkt) } return 1 } // 接收数据 func (p *LatencySimulator) recv(peer int, data []byte, maxsize int) int32 { var it *list.Element if peer == 0 { it = p.p21.Front() if p.p21.Len() == 0 { return -1 } } else { it = p.p12.Front() if p.p12.Len() == 0 { return -1 } } pkt := it.Value.(*DelayPacket) p.current = iclock() if p.current < pkt.ts() { return -2 } if maxsize < pkt.size() { return -3 } if peer == 0 { p.p21.Remove(it) } else { p.p12.Remove(it) } maxsize = pkt.size() copy(data, pkt.ptr()[:maxsize]) return int32(maxsize) } //===================================================================== //===================================================================== // 模拟网络 var vnet *LatencySimulator // 测试用例 func test(mode int) { // 创建模拟网络:丢包率10%,Rtt 60ms~125ms vnet = &LatencySimulator{} vnet.Init(10, 60, 125, 1000) // 创建两个端点的 kcp对象,第一个参数 conv是会话编号,同一个会话需要相同 // 最后一个是 user参数,用来传递标识 output1 := func(buf []byte, size int) { if vnet.send(0, buf, size) != 1 { } } output2 := func(buf []byte, size int) { if vnet.send(1, buf, size) != 1 { } } kcp1 := NewKCP(0x11223344, output1) kcp2 := NewKCP(0x11223344, output2) current := uint32(iclock()) slap := current + 20 index := 0 next := 0 var sumrtt uint32 count := 0 maxrtt := 0 // 配置窗口大小:平均延迟200ms,每20ms发送一个包, // 而考虑到丢包重发,设置最大收发窗口为128 kcp1.WndSize(128, 128) kcp2.WndSize(128, 128) // 判断测试用例的模式 if mode == 0 { // 默认模式 kcp1.NoDelay(0, 10, 0, 0) kcp2.NoDelay(0, 10, 0, 0) } else if mode == 1 { // 普通模式,关闭流控等 kcp1.NoDelay(0, 10, 0, 1) kcp2.NoDelay(0, 10, 0, 1) } else { // 启动快速模式 // 第二个参数 nodelay-启用以后若干常规加速将启动 // 第三个参数 interval为内部处理时钟,默认设置为 10ms // 第四个参数 resend为快速重传指标,设置为2 // 第五个参数 为是否禁用常规流控,这里禁止 kcp1.NoDelay(1, 10, 2, 1) kcp2.NoDelay(1, 10, 2, 1) } buffer := make([]byte, 2000) var hr int32 ts1 := iclock() for { time.Sleep(1 * time.Millisecond) current = uint32(iclock()) kcp1.Update() kcp2.Update() // 每隔 20ms,kcp1发送数据 for ; current >= slap; slap += 20 { buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, uint32(index)) index++ binary.Write(buf, binary.LittleEndian, uint32(current)) // 发送上层协议包 kcp1.Send(buf.Bytes()) //println("now", iclock()) } // 处理虚拟网络:检测是否有udp包从p1->p2 for { hr = vnet.recv(1, buffer, 2000) if hr < 0 { break } // 如果 p2收到udp,则作为下层协议输入到kcp2 kcp2.Input(buffer[:hr], true, false) } // 处理虚拟网络:检测是否有udp包从p2->p1 for { hr = vnet.recv(0, buffer, 2000) if hr < 0 { break } // 如果 p1收到udp,则作为下层协议输入到kcp1 kcp1.Input(buffer[:hr], true, false) //println("@@@@", hr, r) } // kcp2接收到任何包都返回回去 for { hr = int32(kcp2.Recv(buffer[:10])) // 没有收到包就退出 if hr < 0 { break } // 如果收到包就回射 buf := bytes.NewReader(buffer) var sn uint32 binary.Read(buf, binary.LittleEndian, &sn) kcp2.Send(buffer[:hr]) } // kcp1收到kcp2的回射数据 for { hr = int32(kcp1.Recv(buffer[:10])) buf := bytes.NewReader(buffer) // 没有收到包就退出 if hr < 0 { break } var sn uint32 var ts, rtt uint32 binary.Read(buf, binary.LittleEndian, &sn) binary.Read(buf, binary.LittleEndian, &ts) rtt = uint32(current) - ts if sn != uint32(next) { // 如果收到的包不连续 //for i:=0;i<8 ;i++ { //println("---", i, buffer[i]) //} println("ERROR sn ", count, "<->", next, sn) return } next++ sumrtt += rtt count++ if rtt > uint32(maxrtt) { maxrtt = int(rtt) } //println("[RECV] mode=", mode, " sn=", sn, " rtt=", rtt) } if next > 100 { break } } ts1 = iclock() - ts1 names := []string{"default", "normal", "fast"} fmt.Printf("%s mode result (%dms):\n", names[mode], ts1) fmt.Printf("avgrtt=%d maxrtt=%d\n", int(sumrtt/uint32(count)), maxrtt) } func TestNetwork(t *testing.T) { test(0) // 默认模式,类似 TCP:正常模式,无快速重传,常规流控 test(1) // 普通模式,关闭流控等 test(2) // 快速模式,所有开关都打开,且关闭流控 } func BenchmarkFlush(b *testing.B) { kcp := NewKCP(1, func(buf []byte, size int) {}) kcp.snd_buf = make([]segment, 32) for k := range kcp.snd_buf { kcp.snd_buf[k].xmit = 1 kcp.snd_buf[k].resendts = currentMs() + 10000 } b.ResetTimer() b.ReportAllocs() var mu sync.Mutex for i := 0; i < b.N; i++ { mu.Lock() kcp.flush(false) mu.Unlock() } }