Esempio n. 1
0
        public KcpClient(uint conv)
        {
            mHandler = new KcpHandler();

            mConn = new Kcp(conv, mHandler);
            mConn.NoDelay(1, 10, 2, 1);            //fast
            mConn.WndSize(64, 64);
            mConn.SetMtu(512);
        }
Esempio n. 2
0
        public KcpClient(uint conv, IKcpCallback handle)
        {
            if (handle == null)
            {
                throw new Exception("The handler must be not null value");
            }

            mHandler = handle;

            mConn = new Kcp(conv, mHandler);
            mConn.NoDelay(1, 10, 2, 1);            //fast
            mConn.WndSize(64, 64);
            mConn.SetMtu(512);
        }
Esempio n. 3
0
File: Kcp.cs Progetto: summitn/KCP-1
        // 为了减少阅读难度,变量名尽量于 C版 统一

        /*
         * conv 会话ID
         * mtu 最大传输单元
         * mss 最大分片大小
         * state 连接状态(0xFFFFFFFF表示断开连接)
         * snd_una 第一个未确认的包
         * snd_nxt 待发送包的序号
         * rcv_nxt 待接收消息序号
         * ssthresh 拥塞窗口阈值
         * rx_rttvar ack接收rtt浮动值
         * rx_srtt ack接收rtt静态值
         * rx_rto 由ack接收延迟计算出来的复原时间
         * rx_minrto 最小复原时间
         * snd_wnd 发送窗口大小
         * rcv_wnd 接收窗口大小
         * rmt_wnd,	远端接收窗口大小
         * cwnd, 拥塞窗口大小
         * probe 探查变量,IKCP_ASK_TELL表示告知远端窗口大小。IKCP_ASK_SEND表示请求远端告知窗口大小
         * interval    内部flush刷新间隔
         * ts_flush 下次flush刷新时间戳
         * nodelay 是否启动无延迟模式
         * updated 是否调用过update函数的标识
         * ts_probe, 下次探查窗口的时间戳
         * probe_wait 探查窗口需要等待的时间
         * dead_link 最大重传次数
         * incr 可发送的最大数据量
         * fastresend 触发快速重传的重复ack个数
         * nocwnd 取消拥塞控制
         * stream 是否采用流传输模式
         *
         * snd_queue 发送消息的队列
         * rcv_queue 接收消息的队列
         * snd_buf 发送消息的缓存
         * rcv_buf 接收消息的缓存
         * acklist 待发送的ack列表
         * buffer 存储消息字节流的内存
         * output udp发送消息的回调函数
         */

        /// <summary>
        /// create a new kcp control object, 'conv' must equal in two endpoint
        /// from the same connection.
        /// </summary>
        /// <param name="conv_"></param>
        /// <param name="callback"></param>
        public Kcp(uint conv_, IKcpCallback callback)
        {
            conv           = conv_;
            callbackHandle = callback;

            snd_wnd = IKCP_WND_SND;
            rcv_wnd = IKCP_WND_RCV;
            rmt_wnd = IKCP_WND_RCV;
            mtu     = IKCP_MTU_DEF;
            mss     = mtu - IKCP_OVERHEAD;
            buffer  = CreateBuffer(BufferNeedSize);

            rx_rto    = IKCP_RTO_DEF;
            rx_minrto = IKCP_RTO_MIN;
            interval  = IKCP_INTERVAL;
            ts_flush  = IKCP_INTERVAL;
            ssthresh  = IKCP_THRESH_INIT;
            dead_link = IKCP_DEADLINK;
        }
Esempio n. 4
0
        public void Run(uint conv, IKcpCallback kcpCallback)
        {
            _recvFromRemote = new BufferBlock <DataPackage>();
            _recvFromLocal  = new BufferBlock <DataPackage>();

            Conv = conv;

            _kcp = new Kcp(conv, kcpCallback, KcpRentable.Instacne);
            _kcp.NoDelay(1, 10, 2, 1); // 极速模式
            _kcp.WndSize(128, 128);
            _kcp.SetMtu(MTU);

            _tokenSource = new CancellationTokenSource();

            //  这样写的目的,在服务器上,压解缩、加解密可以利用多核(多个KCP连接之间的压解缩、加解密是可以并行的)
            //  update
            Task.Factory.StartNew(async() => {
                //  检测并Flush数据到远端
                while (!_tokenSource.IsCancellationRequested)
                {
                    try {
                        _kcp.Update(DateTime.UtcNow);
                        await _kcp.CheckAwait(DateTime.UtcNow, _tokenSource.Token);
                    }
                    catch (TaskCanceledException) {
                        break;
                    }
                    catch (ObjectDisposedException e) {
                        //  一般情况下,OutPut时使用Socket发送数据时,而Socket被关闭时会进入此分支;暂时这么处理
                        if (e.ObjectName == "System.Net.Sockets.Socket")
                        {
                            break;
                        }
                        Debug.LogErrorFormat("Kcp.updateTask: \r\n {0}", e);
                    }
                }
            }, _tokenSource.Token);

            //  input from lower level
            Task.Factory.StartNew(async() => {
                //  收到 Ack 帧,需要移除 snd_buf;收到数据帧,则需要 Flush Ack
                while (!_tokenSource.IsCancellationRequested)
                {
                    DataPackage package = null;
                    try {
                        package    = await _recvFromRemote.ReceiveAsync(_tokenSource.Token);
                        var result = _kcp.Input(package.MemoryOwner.Memory.Span.Slice(package.Offset, package.Lenght));
                        while (result == 0)
                        {
                            var(memoryOwner, avalidLength) = _kcp.TryRecv();
                            if (memoryOwner == null)
                            {
                                break;
                            }
                            //  在此解压、解密
                            OnRecvKcpPackage?.Invoke(memoryOwner, avalidLength, this);
                        }
                        ;
                    }
                    catch (TaskCanceledException) {
                        _recvFromRemote.Complete();
                        break;
                    }
                    catch (Exception e) {
                        Debug.LogErrorFormat("Kcp.inputTask: \r\n {0}", e);
                    }
                    finally {
                        if (package != null)
                        {
                            package.MemoryOwner.Dispose();
                            DataPackage.Pool.Return(package);
                        }
                    }
                }
            }, _tokenSource.Token);

            //  send by user
            Task.Factory.StartNew(async() => {
                //  有可能需要发送帧,需要Flush Snd_Queue
                while (!_tokenSource.IsCancellationRequested)
                {
                    DataPackage package = null;
                    try {
                        package = await _recvFromLocal.ReceiveAsync(_tokenSource.Token);
                        //  在此压缩、加密
                        _kcp.Send(package.MemoryOwner.Memory.Span.Slice(0, package.Lenght));
                    }
                    catch (TaskCanceledException) {
                        _recvFromLocal.Complete();
                        break;
                    }
                    catch (Exception e) {
                        Debug.LogErrorFormat("Kcp.sendTask: \r\n {0}", e);
                    }
                    finally {
                        if (package != null)
                        {
                            package.MemoryOwner.Dispose();
                            DataPackage.Pool.Return(package);
                        }
                    }
                }
            }, _tokenSource.Token);
        }
Esempio n. 5
0
 public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
     : base(conv_, callback, rentable)
 {
     SegmentManager = Default;
 }
Esempio n. 6
0
 /// <summary>
 /// create a new kcp control object, 'conv' must equal in two endpoint
 /// from the same connection.
 /// </summary>
 /// <param name="conv_"></param>
 /// <param name="callback"></param>
 /// <param name="rentable">可租用内存的回调</param>
 public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
     : base(conv_)
 {
     callbackHandle = callback;
     this.rentable  = rentable;
 }