void TickConnected(uint time) { // detect common events & ping HandleTimeout(time); HandleDeadLink(); HandlePing(time); HandleChoked(); kcp.Update(time); // any message received? if (ReceiveNext(out ArraySegment <byte> message)) { // handshake message? if (Utils.SegmentsEqual(message, Hello)) { Debug.Log("KCP: received handshake"); state = KcpState.Authenticated; OnAuthenticated?.Invoke(); } // otherwise it's random data from the internet, not // from a legitimate player. disconnect. else { Debug.LogWarning("KCP: received random data before handshake. Disconnecting the connection."); Disconnect(); } } }
// SetupKcp creates and configures a new KCP instance. // => useful to start from a fresh state every time the client connects // => NoDelay, interval, wnd size are the most important configurations. // let's force require the parameters so we don't forget it anywhere. protected void SetupKcp(bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = DEFAULT_TIMEOUT) { // set up kcp over reliable channel (that's what kcp is for) kcp = new Kcp(0, RawSendReliable); // set nodelay. // note that kcp uses 'nocwnd' internally so we negate the parameter kcp.SetNoDelay(noDelay ? 1u : 0u, interval, fastResend, !congestionWindow); kcp.SetWindowSize(sendWindowSize, receiveWindowSize); // IMPORTANT: high level needs to add 1 channel byte to each raw // message. so while Kcp.MTU_DEF is perfect, we actually need to // tell kcp to use MTU-1 so we can still put the header into the // message afterwards. kcp.SetMtu(Kcp.MTU_DEF - CHANNEL_HEADER_SIZE); // create message buffers AFTER window size is set // see comments on buffer definition for the "+1" part kcpMessageBuffer = new byte[1 + ReliableMaxMessageSize(receiveWindowSize)]; kcpSendBuffer = new byte[1 + ReliableMaxMessageSize(receiveWindowSize)]; this.timeout = timeout; state = KcpState.Connected; refTime.Start(); }
// disconnect this connection public void Disconnect() { // only if not disconnected yet if (state == KcpState.Disconnected) { return; } // send a disconnect message if (socket.Connected) { try { SendDisconnect(); kcp.Flush(); } catch (SocketException) { // this is ok, the connection was already closed } catch (ObjectDisposedException) { // this is normal when we stop the server // the socket is stopped so we can't send anything anymore // to the clients // the clients will eventually timeout and realize they // were disconnected } } // set as Disconnected, call event Log.Info("KCP Connection: Disconnected."); state = KcpState.Disconnected; OnDisconnected?.Invoke(); }
// NoDelay, interval, window size are the most important configurations. // let's force require the parameters so we don't forget it anywhere. protected void SetupKcp(bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV) { kcp = new Kcp(0, RawSend); // set nodelay. // note that kcp uses 'nocwnd' internally so we negate the parameter kcp.SetNoDelay(noDelay ? 1u : 0u, interval, fastResend, !congestionWindow); kcp.SetWindowSize(sendWindowSize, receiveWindowSize); refTime.Start(); state = KcpState.Connected; Tick(); }
void TickConnected(uint time) { // detect common events & ping HandleTimeout(time); HandleDeadLink(); HandlePing(time); HandleChoked(); kcp.Update(time); // any reliable kcp message received? if (ReceiveNextReliable(out KcpHeader header, out ArraySegment <byte> message)) { // message type FSM. no default so we never miss a case. switch (header) { case KcpHeader.Handshake: { // we were waiting for a handshake. // it proves that the other end speaks our protocol. Log.Info("KCP: received handshake"); state = KcpState.Authenticated; OnAuthenticated?.Invoke(); break; } case KcpHeader.Ping: { // ping keeps kcp from timing out. do nothing. break; } case KcpHeader.Data: case KcpHeader.Disconnect: { // everything else is not allowed during handshake! Log.Warning($"KCP: received invalid header {header} while Connected. Disconnecting the connection."); Disconnect(); break; } } } }
// NoDelay, interval, window size are the most important configurations. // let's force require the parameters so we don't forget it anywhere. protected void SetupKcp(bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV) { // set up kcp over reliable channel (that's what kcp is for) kcp = new Kcp(0, RawSendReliable); // set nodelay. // note that kcp uses 'nocwnd' internally so we negate the parameter kcp.SetNoDelay(noDelay ? 1u : 0u, interval, fastResend, !congestionWindow); kcp.SetWindowSize(sendWindowSize, receiveWindowSize); // IMPORTANT: high level needs to add 1 channel byte to each raw // message. so while Kcp.MTU_DEF is perfect, we actually need to // tell kcp to use MTU-1 so we can still put the header into the // message afterwards. kcp.SetMtu(Kcp.MTU_DEF - CHANNEL_HEADER_SIZE); state = KcpState.Connected; refTime.Start(); }