示例#1
0
        private void Init(string url, uint conv)
        {
            if (conv == 0)
            {
                PlatDependant.LogError("KCP conversation id should not be 0.");
            }
            _Connection       = new UDPClient(url);
            _Conv             = conv;
            _ConnectionHandle = GCHandle.Alloc(_Connection);
            _KCP = KCPLib.kcp_create(conv, (IntPtr)_ConnectionHandle);

            _KCP.kcp_setoutput(Func_KCPOutput);
            _KCP.kcp_nodelay(1, 10, 2, 1);
            // set minrto to 10?

            _Connection.UpdateInterval = 10;
            _Connection.PreDispose     = _con => DisposeSelf();
            _Connection.OnReceive      = (data, cnt, sender) => _KCP.kcp_input(data, cnt);
            _Connection.OnSend         = (data, cnt) =>
            {
                if (cnt > CONST.MTU)
                {
                    int offset = 0;
                    var buffer = BufferPool.GetBufferFromPool();
                    while (cnt > CONST.MTU)
                    {
                        Buffer.BlockCopy(data, offset, buffer, 0, CONST.MTU);
                        _KCP.kcp_send(buffer, CONST.MTU);
                        cnt    -= CONST.MTU;
                        offset += CONST.MTU;
                    }
                    if (cnt > 0)
                    {
                        Buffer.BlockCopy(data, offset, buffer, 0, cnt);
                        _KCP.kcp_send(buffer, cnt);
                    }
                    BufferPool.ReturnBufferToPool(buffer);
                }
                else
                {
                    _KCP.kcp_send(data, cnt);
                }
                return(true);
            };
            _Connection.OnUpdate = _con =>
            {
                _KCP.kcp_update((uint)Environment.TickCount);
                int recvcnt = _KCP.kcp_recv(_RecvBuffer, CONST.MTU);
                if (_OnReceive != null)
                {
                    if (recvcnt > 0)
                    {
                        _OnReceive(_RecvBuffer, recvcnt, _Connection.RemoteEndPoint);
                    }
                }
            };
        }
        public KCPConsultClient(string url) : base(url, 1)
        {
            _Conv = 0;
            _Connection.OnUpdate = _con =>
            {
                _KCP.kcp_update((uint)Environment.TickCount);
                int recvcnt = _KCP.kcp_recv(_RecvBuffer, CONST.MTU);
                if (_Conv == 0)
                {
                    if (recvcnt >= 4)
                    {
                        uint conv = 0;
                        if (BitConverter.IsLittleEndian)
                        {
                            conv = BitConverter.ToUInt32(_RecvBuffer, 0);
                        }
                        else
                        {
                            for (int i = 0; i < 4; ++i)
                            {
                                conv <<= 8;
                                conv  += _RecvBuffer[i];
                            }
                        }
                        if (conv == 0 || conv == 1)
                        {
                            PlatDependant.LogError("KCP conversation id should not be 0 or 1 (with Consult).");
                            throw new ArgumentException("KCP conversation id should not be 0 or 1 (with Consult).");
                        }
                        _KCP.kcp_release();

                        _Conv = conv;
                        _KCP  = KCPLib.kcp_create(conv, (IntPtr)_ConnectionHandle);
                        _KCP.kcp_setoutput(Func_KCPOutput);
                        _KCP.kcp_nodelay(1, 10, 2, 1);
                        _Connection.HoldSending = false;
                    }
                }
                else
                {
                    if (_OnReceive != null)
                    {
                        if (recvcnt > 0)
                        {
                            _OnReceive(_RecvBuffer, recvcnt, _Connection.RemoteEndPoint);
                        }
                    }
                }
            };
            _Connection.PreStart = _con =>
            {
                var guid = _ConnectionGUID.ToByteArray();
                _KCP.kcp_send(guid, guid.Length);
            };
            _Connection.HoldSending = true;
        }
            protected internal ServerConnection(KCPConsultServer server, uint pendingconv) : base(server)
            {
                _PendingConv = pendingconv;
                _Conv        = 0;
                _KCP         = KCPLib.kcp_create(1, (IntPtr)_InfoHandle);
                _Ready       = true;

                _KCP.kcp_setoutput(Func_KCPOutput);
                _KCP.kcp_nodelay(1, 10, 2, 1);
                // set minrto to 10?
            }
            public void SetConv(uint conv)
            {
                if (_Ready)
                {
                    PlatDependant.LogError("Can not change conv. Please create another one.");
                }
                else
                {
                    _Conv  = conv;
                    _KCP   = KCPLib.kcp_create(conv, (IntPtr)_InfoHandle);
                    _Ready = true;

                    _KCP.kcp_setoutput(Func_KCPOutput);
                    _KCP.kcp_nodelay(1, 10, 2, 1);
                    // set minrto to 10?
                }
            }
            protected internal override bool Feed(byte[] data, int cnt, IPEndPoint ep)
            {
                if (_Conv == 0)
                { // this means the conv has not been accepted by client.
                    var conv = ReadConv(data, cnt);
                    if (conv == 0)
                    { // wrong packet.
                        return(false);
                    }
                    else if (conv == 1)
                    { // the unaccepted connection
                        var guid = ReadGUID(data, cnt);
                        if (guid == Guid.Empty)
                        {
                            if (EP != null && EP.Equals(ep))
                            { // this means the ack-packet or something else.
                                return(_KCP.kcp_input(data, cnt) == 0);
                            }
                            else
                            { // client should provide a guid for new connection
                                return(false);
                            }
                        }
                        else
                        {
                            if (_PendingGUID == Guid.Empty)
                            { // accept this connection. bind this connection with the guid.
                                if (_KCP.kcp_input(data, cnt) == 0)
                                {
                                    _PendingGUID = guid;
                                    EP           = ep;
                                    // send the pending conv-id to client.
                                    byte[] buffer = BufferPool.GetBufferFromPool();
                                    if (BitConverter.IsLittleEndian)
                                    {
                                        var pconv = _PendingConv;
                                        for (int i = 0; i < 4; ++i)
                                        {
                                            buffer[i] = (byte)((pconv >> (i * 8)) & 0xFF);
                                        }
                                    }
                                    else
                                    {
                                        var pconv = _PendingConv;
                                        for (int i = 0; i < 4; ++i)
                                        {
                                            buffer[i] = (byte)((pconv >> ((3 - i) * 8)) & 0xFF);
                                        }
                                    }
                                    _KCP.kcp_send(buffer, 4);
                                    BufferPool.ReturnBufferToPool(buffer);
                                    _Connected = true;
                                    return(true);
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                            else
                            { // check the guid.
                                if (_PendingGUID == guid)
                                {
                                    if (_KCP.kcp_input(data, cnt) == 0)
                                    {
                                        if (!ep.Equals(EP))
                                        { // check the ep changed?
                                            EP = ep;
                                        }
                                        return(true);
                                    }
                                    else
                                    {
                                        return(false);
                                    }
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                        }
                    }
                    else
                    {     // the first packet from accepted connection?
                        if (conv == _PendingConv)
                        { // the first packet from accepted connection!
                            // change the kcp to real conv-id.
                            _Conv = conv;
                            _KCP.kcp_release();
                            _KCP = KCPLib.kcp_create(conv, (IntPtr)_InfoHandle);

                            _KCP.kcp_setoutput(Func_KCPOutput);
                            _KCP.kcp_nodelay(1, 10, 2, 1);
                            // set minrto to 10?

                            if (!ep.Equals(EP))
                            { // check the ep changed?
                                EP = ep;
                            }

                            // Feed the data.
                            return(_KCP.kcp_input(data, cnt) == 0);
                        }
                        else
                        { // this packet is for other connection.
                            return(false);
                        }
                    }
                }
                else
                { // the normal connection.
                    return(base.Feed(data, cnt, ep));
                }
            }