protected virtual void SendData(byte[] data, int len) { if (connected) { uint new_conv = 0; KCP.ikcp_decode32u(data, 0, ref new_conv); Log.Error("send_cov=" + new_conv + ",time=" + GetCurrent()); //查找有没有空闲的发送MySocketEventArgs,有就直接拿来用,没有就创建新的.So easy! MySocketEventArgs sendArgs = listArgs.Find(a => a.IsUsing == false); if (sendArgs == null) { sendArgs = initSendArgs(); } lock (sendArgs) //要锁定,不锁定让别的线程抢走了就不妙了. { sendArgs.IsUsing = true; sendArgs.SetBuffer(data, 0, len); } if (!clientSocket.SendToAsync(sendArgs)) { sendArgs.IsUsing = false; ProcessSend(sendArgs); } } else { throw new SocketException((Int32)SocketError.NotConnected); } }
void process_connect_packet() { mRecvQueue.Switch(); if (!mRecvQueue.Empty()) { var buf = mRecvQueue.Pop(); UInt32 conv = 0; KCP.ikcp_decode32u(buf, 0, ref conv); if (conv <= 0) { throw new Exception("inlvaid connect back packet"); } init_kcp(conv); mInConnectStage = false; mConnectSucceed = true; m_connectStatusCallback(NetworkState.Connected); //evHandler(cliEvent.Connected, null, null); } }
void OnReceive(IAsyncResult ar) { try { if (ar.IsCompleted) { IPEndPoint ipEndpoint = null; byte[] data = client.EndReceive(ar, ref ipEndpoint); if (!(data.Length < KCP.IKCP_OVERHEAD)) { lock (kcpManager) { uint new_conv = 0; KCP.ikcp_decode32u(data, 0, ref new_conv); if (kcpManager.ContainsKey(new_conv)) { kcpManager[new_conv].Input(data); } } } } } catch (SocketException e) { // This happens when a client disconnects, as we fail to send to that port. } client.BeginReceive(OnReceive, null); }
private void OnRecive(IAsyncResult ar) { if (client == null) { return; } try { byte[] buf = client.EndReceive(ar, ref remoteEndPoint); if (buf == null || buf.Length <= 0) { Debug.LogError("Recive buff is null"); return; } if (buf.Length < KCP.IKCP_OVERHEAD) { return; } UInt32 ts = 0; UInt32 conv = 0; byte cmd = 0; KCP.ikcp_decode32u(buf, 0, ref conv); if (this.conv != conv) { return; } KCP.ikcp_decode8u(buf, 4, ref cmd); if (cmd == KCP.IKCP_CMD_ACK) { //拦截ack包中的时间戳,作为ping值计算 KCP.ikcp_decode32u(buf, 8, ref ts); App.Trigger(EventName.Ping, (SystemTime.Clock() - ts)); } //推进kcp处理 channel.Input(buf); client.BeginReceive(OnRecive, null); } catch (Exception) { Debug.LogError("host is closed."); Dispose(); } }
/// <summary> /// 和Update同一个线程调用 /// </summary> internal void process_recv_queue(byte[] datas) { #if DEV IRQLog.AppLog.Log(this.m_netIndex.ToString() + ",接收1"); #endif if (m_Kcp != null && datas != null) { m_Kcp.Input(datas); m_NeedUpdateFlag = true; for (var size = m_Kcp.PeekSize(); size > 0; size = m_Kcp.PeekSize()) { byte[] buffer; buffer = (UdpLibConfig.UseBytePool ? m_KCPServer.BytePool.Rent(size) : new byte[size]); try { if (m_Kcp.Recv(buffer) > 0) { m_LastRecvTimestamp = m_KCPServer.m_watch.Elapsed; uint key = 0; KCP.ikcp_decode32u(buffer, 0, ref key); if (m_KCPServer.IsClientKeyCorrect(this.m_netIndex, (int)key) == false) { #if DEBUG Console.WriteLine("index:{0} key 不对", this.m_netIndex); #endif m_KCPServer.BytePool.Return(buffer, true); DisposeReason = ClientSessionDisposeReason.IndexKeyError; //key不对 Dispose(); return; } #if DEV IRQLog.AppLog.Log(this.m_netIndex.ToString() + ",接收2"); #endif m_KCPServer.OnRecvData(this, buffer, 0, size); } } finally { if (UdpLibConfig.UseBytePool) { m_KCPServer.BytePool.Return(buffer, true); } } } } }
public int Decode(byte[] buf, int size) { uint n = 0; KCP.ikcp_decode32u(buf, 0, ref n); if (n >= (uint)KcpCmd.KCP_CMD_COUNT) { return(-1); } cmd = (KcpCmd)n; if (cmd != KcpCmd.KCP_CMD_CONNECT_REQ) { KCP.ikcp_decode32u(buf, 4, ref conv); } return(0); }
private void ProcessRecvQueue() { while (!RecvQueue.IsEmpty) { SocketAsyncEventArgs e = null; bool isSuccess = RecvQueue.TryDequeue(out e); if (!isSuccess || e == null) { continue; } if (e.BytesTransferred == 0) { mSAEPool.PutObject(e); continue; } //handshake with {0,0,0,0} at the first if (Helper.IsHandshakeDataRight(e.Buffer, e.Offset, e.BytesTransferred)) { uint conv = Helper.iclock(); var newSession = new KCPClientSession(conv); newSession.ClientEndPoint = e.RemoteEndPoint; newSession.KCPOutput = SendWithSession; newSession.RecvDataHandler = RecvDataHandler; mSessions.TryAdd(conv, newSession); KCP.ikcp_encode32u(e.Buffer, e.BytesTransferred, conv); e.SetBuffer(0, e.BytesTransferred + 4); if (!mServerSocket.SendToAsync(e)) { ProcessSend(e); } Console.WriteLine("Handshake from:" + e.RemoteEndPoint.ToString()); } else { uint conv = 0; KCP.ikcp_decode32u(e.Buffer, e.Offset, ref conv); KCPClientSession session = null; mSessions.TryGetValue(conv, out session); if (session != null) { session.processRecvQueue(e); } mSAEPool.PutObject(e); } } }
// This method is invoked when an asynchronous receive operation completes. // If the remote host closed the connection, then the socket is closed. // If data was received then the data is echoed back to the client. // private void ProcessReceive(SocketAsyncEventArgs e) { try { Log.Error("EEE=" + e.BytesTransferred + "," + e.SocketError + "," + e.Count); if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { MySocketEventArgs eventArgs = this.receiveEventArgsPool.Rent <MySocketEventArgs>(); this.clientSocket.ReceiveFromAsync(eventArgs); //读取数据 byte[] data = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); if (!(data.Length < KCP.IKCP_OVERHEAD)) { lock (kcpManager) { uint new_conv = 0; KCP.ikcp_decode32u(data, 0, ref new_conv); if (kcpManager.ContainsKey(new_conv)) { kcpManager[new_conv].Input(data); } } } this.receiveEventArgsPool.Return((MySocketEventArgs)e); /* * if (!token.ReceiveFromAsync(e)) * this.ProcessReceive(e); */ } else { ProcessError(e); } } catch (Exception xe) { Console.WriteLine(xe.Message); } }
/// <summary> /// 接收消息线程 /// </summary> private void OnRecive(IAsyncResult ar) { try { remoteEndPoint = null; byte[] buf = client.EndReceive(ar, ref remoteEndPoint); //如果缓冲区为null 或 长度少于等于0,则断线 if (buf == null || buf.Length <= 0) { Dispose(); Debug.LogError("kcp buff is None"); return; } //获取会话conv UInt32 conv = 0; KCP.ikcp_decode32u(buf, 0, ref conv); //查找信道池,没有则建立新的 KChannel channel; if (!channels.TryGetValue(conv, out channel)) { channel = new KChannel(conv, client, remoteEndPoint) { OnRecive = OnRecive }; channel.OnConnectState = OnConnectState; channels.Add(conv, channel); } channel.Input(buf); //再次调用异步接收 client.BeginReceive(OnRecive, null); } catch (Exception) { //TODO 触发此处异常,一般由于客户端主动关闭致使S端无法返回数据包到C端。 //TODO 服务器在此类异常中不需要关闭,只需要处理掉断开连接的C端 } }
/// <summary> /// 是否是正确的握手响应 /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="size"></param> /// <param name="index"></param> /// <param name="key"></param> /// <returns></returns> internal static bool IsHandshakeDataRight(byte[] buffer, int offset, int size, out uint index, out uint key) { index = 0; key = 0; if (size < UdpLibConfig.HandshakeDataSize) { return(false); } for (int i = 0; i < UdpLibConfig.HandshakeHeadData.Length; i++) { if (buffer[offset + i] != UdpLibConfig.HandshakeHeadData[i]) { return(false); } } KCP.ikcp_decode32u(buffer, offset + UdpLibConfig.HandshakeHeadData.Length, ref index); KCP.ikcp_decode32u(buffer, offset + UdpLibConfig.HandshakeHeadData.Length + 4, ref key); return(true); }
private void ProcessConnectQueue() { if (!recvQueue.IsEmpty) { byte[] data = null; bool isSuccess = recvQueue.TryDequeue(out data); if (!isSuccess || data == null) { return; } if (Helper.IsHandshakeDataRight(data, 0, data.Length)) { UInt32 conv = 0; KCP.ikcp_decode32u(data, Helper.HandshakeHeadData.Length, ref conv); init_kcp(conv); status = ClientStatus.Connected; Console.WriteLine("Handshake Success"); } } }
protected void UpdateKcp() { while (connected) { long start = GetCurrent(); lock (kcpManager) { List <uint> pp = new List <uint>(kcpManager.Keys); for (var index = 0; index < pp.Count; index++) //foreach (KeyValuePair<uint, KCP> kv in kcpManager) { KeyValuePair <uint, KCP> kv = new KeyValuePair <uint, KCP>(pp[index], kcpManager[pp[index]]); kv.Value.Update((uint)start); int len = kv.Value.Recv(kcpDataCache); if (len > 0) { byte[] data = new byte[len]; Array.Copy(kcpDataCache, data, len); lock (m_buffer) { m_buffer.AddRange(data); } //DoReceiveEvent() do { int headLength = Marshal.SizeOf(typeof(CommonPackHead)); // 判断包头是否满足 if (headLength <= m_buffer.Count) { byte[] lenBytes = m_buffer.GetRange(0, headLength).ToArray(); //分配结构体内存空间 IntPtr structPtr = Marshal.AllocHGlobal(headLength); //将byte数组拷贝到分配好的内存空间 Marshal.Copy(lenBytes, 0, structPtr, headLength); //将内存空间转换为目标结构体 CommonPackHead packHead = (CommonPackHead)Marshal.PtrToStructure(structPtr, typeof(CommonPackHead)); //释放内存空间 Marshal.FreeHGlobal(structPtr); if (packHead.msg_len <= m_buffer.Count) { //包够长时,则提取出来,交给后面的程序去处理 byte[] recv = m_buffer.GetRange(0, (int)packHead.msg_len).ToArray(); lock (m_buffer) { m_buffer.RemoveRange(0, (int)packHead.msg_len); } //将数据包交给前台去处理 DoReceiveEvent(packHead, recv); } else { break; } } else { // if (4 == len) { uint new_conv = 0; KCP.ikcp_decode32u(data, 0, ref new_conv); if (!kcpManager.ContainsKey(new_conv)) { kcpManager.Add(new_conv, new KCP(new_conv, SendData)); lock (m_buffer) { m_buffer.RemoveRange(0, 4); } } usingConv = new_conv; Log.Error("usingConv=" + new_conv); } //长度不够,还得继续接收,需要跳出循环 break; } } while (m_buffer.Count > 4); } } } long after = GetCurrent(); if (after - start < ThreadGap) { Thread.Sleep((int)(ThreadGap + start - after)); } } }
void ProcessRecvQueue(UInt32 now) { if (recvQueue_.Empty()) { recvQueue_.Switch(); } while (status_ == Status.Connected && !recvQueue_.Empty()) { var buf = recvQueue_.Pop(); UInt32 conv = 0; if (KCP.ikcp_decode32u(buf, 0, ref conv) < 0) { // handle kcp command continue; } if (conv < KcpConst.KCP_MIN_CONV) { if (kcpCommand_.Decode(buf, buf.Length) < 0) { continue; } if (conv_ != kcpCommand_.conv) { continue; } lastRecvTime_ = now; switch (kcpCommand_.cmd) { case KcpCmd.KCP_CMD_DISCONNECT: { OnDisconnect(); } break; case KcpCmd.KCP_CMD_HEARTBEAT: { } break; } } else { if (conv_ != kcpCommand_.conv) { continue; } lastRecvTime_ = now; kcp_.Input(buf); needUpdate_ = true; for (var size = kcp_.PeekSize(); size > 0; size = kcp_.PeekSize()) { var buffer = new byte[size]; if (kcp_.Recv(buffer) > 0) { eventCallback_(conv, KcpEvent.KCP_EV_MSG, buffer, null); } } } } }
// 测试用例 static void KCPTest(int mode) { // 创建模拟网络:丢包率10%,Rtt 60ms~125ms vnet = new LatencySimulator(10, 60, 125); // 创建两个端点的 kcp对象,第一个参数 conv是会话编号,同一个会话需要相同 // 最后一个是 user参数,用来传递标识 var kcp1 = new KCP(0x11223344, 1); var kcp2 = new KCP(0x11223344, 2); // 设置kcp的下层输出,这里为 udp_output,模拟udp网络输出函数 kcp1.SetOutput(udp_output); kcp2.SetOutput(udp_output); UInt32 current = Utils.iclock(); UInt32 slap = current + 20; UInt32 index = 0; UInt32 next = 0; Int64 sumrtt = 0; int count = 0; int 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 // 启动快速模式 { // 第1个参数 nodelay-启用以后若干常规加速将启动 // 第2个参数 interval为内部处理时钟,默认设置为 10ms // 第3个参数 resend为快速重传指标,设置为2 // 第4个参数 为是否禁用常规流控,这里禁止 kcp1.NoDelay(1, 10, 2, 1); kcp2.NoDelay(1, 10, 2, 1); kcp1.SetMinRTO(10); kcp1.SetFastResend(1); } var buffer = new byte[2000]; int hr = 0; UInt32 ts1 = Utils.iclock(); while (true) { Thread.Sleep(1); current = Utils.iclock(); kcp1.Update(current); kcp2.Update(current); // 每隔 20ms,kcp1发送数据 for (; current >= slap; slap += 20) { KCP.ikcp_encode32u(buffer, 0, index++); KCP.ikcp_encode32u(buffer, 4, current); // 发送上层协议包 kcp1.Send(buffer, 0, 8); } // 处理虚拟网络:检测是否有udp包从p1->p2 while (true) { hr = vnet.Recv(1, buffer, 2000); if (hr < 0) { break; } // 如果 p2收到udp,则作为下层协议输入到kcp2 hr = kcp2.Input(buffer, 0, hr); Debug.Assert(hr >= 0); } // 处理虚拟网络:检测是否有udp包从p2->p1 while (true) { hr = vnet.Recv(0, buffer, 2000); if (hr < 0) { break; } // 如果 p1收到udp,则作为下层协议输入到kcp1 hr = kcp1.Input(buffer, 0, hr); Debug.Assert(hr >= 0); } // kcp2接收到任何包都返回回去 while (true) { hr = kcp2.Recv(buffer, 0, 10); if (hr < 0) { break; } // 如果收到包就回射 hr = kcp2.Send(buffer, 0, hr); Debug.Assert(hr >= 0); } // kcp1收到kcp2的回射数据 while (true) { hr = kcp1.Recv(buffer, 0, 10); if (hr < 0) // 没有收到包就退出 { break; } int offset = 0; UInt32 sn = KCP.ikcp_decode32u(buffer, ref offset); UInt32 ts = KCP.ikcp_decode32u(buffer, ref offset); UInt32 rtt = current - ts; if (sn != next) { // 如果收到的包不连续 Console.WriteLine(String.Format("ERROR sn {0}<->{1}", count, next)); return; } next++; sumrtt += rtt; count++; if (rtt > maxrtt) { maxrtt = (int)rtt; } Console.WriteLine(String.Format("[RECV] mode={0} sn={1} rtt={2}", mode, sn, rtt)); } if (next > 1000) { break; } } ts1 = Utils.iclock() - ts1; var names = new string[3] { "default", "normal", "fast" }; Console.WriteLine("{0} mode result ({1}ms):", names[mode], ts1); Console.WriteLine("avgrtt={0} maxrtt={1} tx={2}", sumrtt / count, maxrtt, vnet.tx1); Console.WriteLine("Press any key to next..."); Console.Read(); }
// Test case static void KCPTest(int mode) { // Create an analog network: 10% packet loss rate,Rtt 60ms~125ms vnet = new LatencySimulator(10, 60, 125); // Create a kcp object with two endpoints, the first parameter conv is the session number, the same session needs to be the same // The last one is the user parameter, which is used to pass the identifier. var kcp1 = new KCP(0x11223344, 1); var kcp2 = new KCP(0x11223344, 2); // Set the lower output of kcp, here udp_output, simulate udp network output function kcp1.SetOutput(udp_output); kcp2.SetOutput(udp_output); UInt32 current = Utils.iclock(); UInt32 slap = current + 20; UInt32 index = 0; UInt32 next = 0; Int64 sumrtt = 0; int count = 0; int maxrtt = 0; // Configuration window size: average delay 200ms, send a packet every 20ms, // Considering the packet loss retransmission, set the maximum receiving and sending window to 128. kcp1.WndSize(128, 128); kcp2.WndSize(128, 128); if (mode == 0) //Default mode { kcp1.NoDelay(0, 10, 0, 0); kcp2.NoDelay(0, 10, 0, 0); } else if (mode == 1) // Normal mode, turn off flow control, etc. { kcp1.NoDelay(0, 10, 0, 1); kcp2.NoDelay(0, 10, 0, 1); } else //Start fast mode { // 1st parameter nodelay-enabled after some regular acceleration will start // The second parameter interval is the internal processing clock. The default setting is 10ms. // The third parameter resend is the fast retransmission indicator, set to 2 // The fourth parameter is whether to disable regular flow control, this is forbidden here. kcp1.NoDelay(1, 10, 2, 1); kcp2.NoDelay(1, 10, 2, 1); kcp1.SetMinRTO(10); kcp1.SetFastResend(1); } var buffer = new byte[2000]; int hr = 0; UInt32 ts1 = Utils.iclock(); while (true) { Thread.Sleep(1); current = Utils.iclock(); kcp1.Update(current); kcp2.Update(current); // Kcp1 sends data every 20ms for (; current >= slap; slap += 20) { KCP.ikcp_encode32u(buffer, 0, index++); KCP.ikcp_encode32u(buffer, 4, current); // Send the upper layer protocol packet kcp1.Send(buffer, 0, 8); } //Handling virtual networks: detecting if there are udp packets from p1->p2 while (true) { hr = vnet.Recv(1, buffer, 2000); if (hr < 0) { break; } //If p2 receives udp, it is input to kcp2 as the underlying protocol. hr = kcp2.Input(buffer, 0, hr); Debug.Assert(hr >= 0); } // Handling virtual networks: detecting if there are udp packets from p2->p1 while (true) { hr = vnet.Recv(0, buffer, 2000); if (hr < 0) { break; } // If p1 receives udp, it is input to kcp1 as the underlying protocol. hr = kcp1.Input(buffer, 0, hr); Debug.Assert(hr >= 0); } // Kcp2 receives any package and returns it. while (true) { hr = kcp2.Recv(buffer, 0, 10); if (hr < 0) { break; } //If you receive the package, it will return hr = kcp2.Send(buffer, 0, hr); Debug.Assert(hr >= 0); } // Kcp1 receives the echo data of kcp2 while (true) { hr = kcp1.Recv(buffer, 0, 10); if (hr < 0) // Exit without receiving the package { break; } int offset = 0; UInt32 sn = KCP.ikcp_decode32u(buffer, ref offset); UInt32 ts = KCP.ikcp_decode32u(buffer, ref offset); UInt32 rtt = current - ts; if (sn != next) { // If the received packet is not continuous Console.WriteLine(String.Format("ERROR sn {0}<->{1}", count, next)); return; } next++; sumrtt += rtt; count++; if (rtt > maxrtt) { maxrtt = (int)rtt; } Console.WriteLine(String.Format("[RECV] mode={0} sn={1} rtt={2}", mode, sn, rtt)); } if (next > 1000) { break; } } ts1 = Utils.iclock() - ts1; var names = new string[3] { "default", "normal", "fast" }; Console.WriteLine("{0} mode result ({1}ms):", names[mode], ts1); Console.WriteLine("avgrtt={0} maxrtt={1} tx={2}", sumrtt / count, maxrtt, vnet.tx1); Console.WriteLine("Press any key to next..."); Console.Read(); }
private void DealData(IPEndPoint RemoteEndPoint, byte[] buffer) { try { uint index = 0, key = 0; if (IsHandshake(buffer, 0, buffer.Length, out index, out key)) {//先握手,使用纯udp进行握手,8字节0xFF+4字节conv+4字节key var c = GetSession(index); uint cc = 0; KCP.ikcp_decode32u(buffer, 16, ref cc); if (c == null) { bool add = true; //新连接处理,如果返回false,则不予处理,可以用来进行非法连接的初步处理 if (NewSessionProcessor != null) { add = NewSessionProcessor.OnNewSession(index, RemoteEndPoint); } if (add == false) { return; } c = AddSession(RemoteEndPoint, index); c.m_KCPServer = this; c.m_LastRecvTimestamp = m_watch.Elapsed; OnNewClientSession(c, buffer, 0, buffer.Length); } else { Log.Info("====重新设置EndPoint===="); c.EndPoint = RemoteEndPoint; //如果客户端关闭并且立刻重连,这时候是连不上的,因为KCP中原有的数据不能正确处理 //c.ResetKCP(); } c.Status = ClientSessionStatus.Connected; //回发握手请求 UDPClient.BeginSend(buffer, buffer.Length, RemoteEndPoint, (IAsyncResult iar) => { UDPClient.EndSend(iar); }, null); } else { try { KCP.ikcp_decode32u(buffer, 0, ref index); var c = GetSession(index); if (c != null && c.Status == ClientSessionStatus.Connected) { //Debug.Assert(c.EndPoint.ToString() == RemoteEndPoint.ToString()); if (c.EndPoint.ToString() != RemoteEndPoint.ToString()) { c.EndPoint = RemoteEndPoint; Log.Error("==ClientSessionStatus.Connected=="); } c.AddRecv(buffer); } } catch (Exception ex) { Log.Error("==DealData error:" + ex.ToString()); } } } catch (Exception ex) { Log.Error("DealData Error:" + ex.ToString()); } }