//User to KCP public void Send(byte[] data) { var pack = new KCPPacket() { data = data, }; sendQueue.Enqueue(pack); }
//UDP to KCP public void Input(byte[] data, int length) { var pack = new KCPPacket(); pack.DecodeData(data, length); lock (recvQueue) { recvQueue.Enqueue(pack); } }
private void HandleRecv() { var c = 0; while (c <= maxRecvNum) { KCPPacket recPack = null; lock (recvQueue) { //服务器接收到客户端的ACK if (recvQueue.Count > 0) { recPack = recvQueue.Dequeue(); } } if (recPack != null) { c++; var seg = recPack; if (seg.isAck) { foreach (var s in sendBuf) { if (s.sn == seg.sn) { s.cmd = KCPPacketCMD.CMD_ACKED; break; } } } else //只发送一次ACK给服务器 失败则服务器自己报文重发 //服务器发送的新的报文 只接受服务器区间内的报文 //拒绝服务器重复的报文winStart = 0 winEnd = 2 //如果处理过了则不再处理 //服务器和每个客户端有独立的连接和独立的序号顺序 //连接建立的时刻就是 0 2 确定了 { var srvSn = seg.sn; var ret = CheckInWin(srvSn, ackWinStart, ackWinEnd); //窗口边界的怎么处理不知道是否已经验证过了两倍大小的接受窗口 //sendSize 2 ackSz = 4 if (ret) { var sendACK = new KCPPacket(); sendACK.isAck = true; sendACK.sn = seg.sn; sendACK.EncodeFull(); //sendQueue.Enqueue(sendACK); outputFunc(sendACK); //立即发送ACK var tailHalfST = ackWinStart + windSz; var tailHalfEND = ackWinEnd; //数据出现在后半端,则可以移动接受窗口了 if (CheckInWin(srvSn, tailHalfST, tailHalfEND)) { ackWinStart++; ackWinEnd++; ackYet.Remove(ackWinStart - 1); recvList.MoveStart(); Console.WriteLine("WinSz:" + ackWinStart + ":" + ackWinEnd); } if (!ackYet.Contains(srvSn)) { ackYet.Add(srvSn); //recvBuf.Enqueue(seg); recvList.AddPacket(seg, srvSn - ackWinStart); CheckLoopList(); Console.WriteLine("Ack:" + srvSn); } } } } else { break; } } }
//将新来的报文放到某个slot上面 public void AddPacket(KCPPacket pack, UInt32 index) { var id = (start + index) % (total); recvSlots[(int)id] = pack; }