Beispiel #1
0
        public int Encode(byte[] buf, int size)
        {
            if (size < 8)
            {
                return(-1);
            }

            KCP.ikcp_encode32u(buf, 0, (uint)cmd);
            if (cmd == KcpCmd.KCP_CMD_CONNECT_REQ)
            {
                return(4);
            }
            KCP.ikcp_encode32u(buf, 4, conv);
            return(8);
        }
Beispiel #2
0
    /// <summary>
    /// 发送数据。发送时,默认在头部加上4字节的key
    /// </summary>
    /// <param name="buf"></param>
    public void Send(byte[] buf)
    {
        byte[] newbuf = new byte[buf.Length + 4];
        //把key附上,服务端合法性检测用
        KCP.ikcp_encode32u(newbuf, 0, (uint)m_Key);
        Array.Copy(buf, 0, newbuf, 4, buf.Length);
        m_LastSendTimestamp = UnityEngine.Time.time;
        m_Kcp.Send(newbuf);
        m_NeedUpdateFlag = true;
        var e = Event;

        if (e != null)
        {
            e(UdpClientEvents.Send, buf);
        }
    }
Beispiel #3
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);
                }
            }
        }
Beispiel #4
0
    //发送握手数据 16字节 8字节头+4字节index+4字节key
    private void SendHandshake()
    {
        if (UdpLibConfig.DebugLevel != (int)UdpLibLogLevel.None)
        {
#if DEBUG
            Console.WriteLine("发送握手数据");
#endif
        }

        Interlocked.Increment(ref m_pktCounter);
        byte[] buf = new byte[UdpLibConfig.HandshakeDataSize + 4];
        Array.Copy(UdpLibConfig.HandshakeHeadData, buf, UdpLibConfig.HandshakeHeadData.Length);
        KCP.ikcp_encode32u(buf, UdpLibConfig.HandshakeHeadData.Length, m_NetIndex);
        KCP.ikcp_encode32u(buf, UdpLibConfig.HandshakeHeadData.Length + 4, (uint)m_Key);
        KCP.ikcp_encode32u(buf, UdpLibConfig.HandshakeHeadData.Length + 8, (uint)m_pktCounter);
        //m_UdpClient.Send(buf, buf.Length);
        m_UdpClient.BeginSend(buf, buf.Length, server_addr, (IAsyncResult iar) => { m_UdpClient.EndSend(iar); }, null);
#if DEV
        string s = string.Format("{0},发送握手数据,{1}", m_NetIndex, m_pktCounter.ToString());
        IRQLog.AppLog.Log(s);
        Console.WriteLine(s);
#endif
    }
Beispiel #5
0
        // 测试用例
        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();
        }
Beispiel #6
0
        // 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();
        }