async UniTaskVoid Tick()
        {
            try
            {
                Thread.VolatileWrite(ref lastReceived, stopWatch.ElapsedMilliseconds);

                while (open)
                {
                    long now      = stopWatch.ElapsedMilliseconds;
                    long received = Thread.VolatileRead(ref lastReceived);
                    if (now > received + Timeout)
                    {
                        break;
                    }

                    kcp.Update((uint)now);

                    uint check = kcp.Check((uint)now);

                    if (check <= now)
                    {
                        check = (uint)(now + 10);
                    }

#if NETSTANDARD
                    await UniTask.Delay((int)(check - now));
#else
                    await Task.Delay((int)(check - now));
#endif
                }
            }
            catch (SocketException)
            {
                // this is ok, the connection was closed
            }
            catch (ObjectDisposedException)
            {
                // fine,  socket was closed,  no more ticking needed
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
            }
            finally
            {
                open = false;
                dataAvailable?.TrySetResult();
                Close();
            }
        }
        private void SendWithChecksum(byte [] data, int length)
        {
            // add a CRC64 checksum in the reserved space
            ulong crc     = Crc64.Compute(data, RESERVED, length - RESERVED);
            var   encoder = new Encoder(data, 0);

            encoder.Encode64U(crc);
            RawSend(data, length);

            if (kcp.WaitSnd > 1000)
            {
                Debug.LogWarningFormat("Too many packets waiting in the send queue {0}, you are sending too much data,  the transport can't keep up", kcp.WaitSnd);
            }
        }