| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299 | using System.Buffers;using System.Buffers.Binary;using System.Collections.Concurrent;using System.Collections.Generic;using System.Runtime.CompilerServices;using Fort23.UTool;using static System.Math;using BufferOwner = System.Buffers.IMemoryOwner<byte>;namespace System.Net.Sockets.Kcp{    public abstract class KcpConst    {        /// <summary>        /// <para>https://github.com/skywind3000/kcp/issues/53</para>        /// 按照 C版 设计,使用小端字节序        /// </summary>        public static bool IsLittleEndian = true;        // 为了减少阅读难度,变量名尽量于 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发送消息的回调函数        */        #region Const        public const int IKCP_RTO_NDL = 30; // no delay min rto        public const int IKCP_RTO_MIN = 100; // normal min rto        public const int IKCP_RTO_DEF = 200;        public const int IKCP_RTO_MAX = 60000;        /// <summary>        /// 数据报文        /// </summary>        public const int IKCP_CMD_PUSH = 81; // cmd: push data        /// <summary>        /// 确认报文        /// </summary>        public const int IKCP_CMD_ACK = 82; // cmd: ack        /// <summary>        /// 窗口探测报文,询问对端剩余接收窗口的大小.        /// </summary>        public const int IKCP_CMD_WASK = 83; // cmd: window probe (ask)        /// <summary>        /// 窗口通知报文,通知对端剩余接收窗口的大小.        /// </summary>        public const int IKCP_CMD_WINS = 84; // cmd: window size (tell)        /// <summary>        /// IKCP_ASK_SEND表示请求远端告知窗口大小        /// </summary>        public const int IKCP_ASK_SEND = 84; // need to send IKCP_CMD_WASK        /// <summary>        /// IKCP_ASK_TELL表示告知远端窗口大小。        /// </summary>        public const int IKCP_ASK_TELL = 84; // need to send IKCP_CMD_WINS        public const int IKCP_WND_SND = 256;        /// <summary>        /// 接收窗口默认值。必须大于最大分片数        /// </summary>        public const int IKCP_WND_RCV = 512; // must >= max fragment size        /// <summary>        /// 默认最大传输单元 常见路由值 1492 1480  默认1400保证在路由层不会被分片        /// </summary>        public const int IKCP_MTU_DEF = 1400;        public const int IKCP_ACK_FAST = 3;        public const int IKCP_INTERVAL = 5;        public const int IKCP_OVERHEAD = 24;        public const int IKCP_DEADLINK = 20;        public const int IKCP_THRESH_INIT = 2;        public const int IKCP_THRESH_MIN = 2;        /// <summary>        /// 窗口探查CD        /// </summary>        public const int IKCP_PROBE_INIT = 7000; // 7 secs to probe window size        public const int IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window        public const int IKCP_FASTACK_LIMIT = 5; // max times to trigger fastack        #endregion    }    /// <summary>    /// https://luyuhuang.tech/2020/12/09/kcp.html    /// https://github.com/skywind3000/kcp/wiki/Network-Layer    /// <para>外部buffer ----拆分拷贝----等待列表 -----移动----发送列表----拷贝----发送buffer---output</para>    /// https://github.com/skywind3000/kcp/issues/118#issuecomment-338133930    /// </summary>    public partial class KcpCore<Segment> : KcpConst, IKcpSetting, IKcpUpdate, IDisposable        where Segment : IKcpSegment    {        internal protected IKcpCallback callbackHandle;        internal protected IKcpOutputWriter OutputWriter;        public KcpCore(uint conv_)        {            conv = conv_;            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;            fastlimit = IKCP_FASTACK_LIMIT;            dead_link = IKCP_DEADLINK;        }        public ISegmentManager<Segment> SegmentManager { get; set; }        protected static uint Ibound(uint lower, uint middle, uint upper)        {            return Min(Max(lower, middle), upper);        }        protected static int Itimediff(uint later, uint earlier)        {            return ((int)(later - earlier));        }        internal protected virtual BufferOwner CreateBuffer(int needSize)        {            return new KcpInnerBuffer(needSize);        }        internal protected class KcpInnerBuffer : BufferOwner        {            private readonly Memory<byte> _memory;            bool alreadyDisposed = false;            public KcpInnerBuffer(int size)            {                _memory = new Memory<byte>(new byte[size]);            }            public Memory<byte> Memory            {                get                {                    if (alreadyDisposed)                    {                        throw new ObjectDisposedException(nameof(KcpInnerBuffer));                    }                    return _memory;                }            }            public void Dispose()            {                alreadyDisposed = true;            }        }        #region kcp members        /// <summary>        /// 频道号        /// </summary>        public uint conv { get; protected set; }        /// <summary>        /// 最大传输单元(Maximum Transmission Unit,MTU)        /// </summary>        protected uint mtu;        /// <summary>        /// 缓冲区最小大小        /// </summary>        protected int BufferNeedSize        {            [MethodImpl(MethodImplOptions.AggressiveInlining)]            get { return (int)((mtu /* + IKCP_OVERHEAD*/) /** 3*/); }        }        /// <summary>        /// 最大报文段长度        /// </summary>        protected uint mss;        /// <summary>        /// 连接状态(0xFFFFFFFF表示断开连接)        /// </summary>        protected int state;        /// <summary>        /// 第一个未确认的包        /// </summary>        protected uint snd_una;        /// <summary>        /// 待发送包的序号        /// </summary>        protected uint snd_nxt;        /// <summary>        /// 下一个等待接收消息ID,待接收消息序号        /// </summary>        protected uint rcv_nxt;        protected uint ts_recent;        protected uint ts_lastack;        /// <summary>        /// 拥塞窗口阈值        /// </summary>        protected uint ssthresh;        /// <summary>        /// ack接收rtt浮动值        /// </summary>        protected uint rx_rttval;        /// <summary>        /// ack接收rtt静态值        /// </summary>        protected uint rx_srtt;        /// <summary>        /// 由ack接收延迟计算出来的复原时间。Retransmission TimeOut(RTO), 超时重传时间.        /// </summary>        protected uint rx_rto;        /// <summary>        /// 最小复原时间        /// </summary>        protected uint rx_minrto;        /// <summary>        /// 发送窗口大小        /// </summary>        protected uint snd_wnd;        /// <summary>        /// 接收窗口大小        /// </summary>        protected uint rcv_wnd;        /// <summary>        /// 远端接收窗口大小        /// </summary>        protected uint rmt_wnd;        /// <summary>        /// 拥塞窗口大小        /// </summary>        protected uint cwnd;        /// <summary>        /// 探查变量,IKCP_ASK_TELL表示告知远端窗口大小。IKCP_ASK_SEND表示请求远端告知窗口大小        /// </summary>        protected uint probe;        protected uint current;        /// <summary>        /// 内部flush刷新间隔        /// </summary>        protected uint interval;        /// <summary>        /// 下次flush刷新时间戳        /// </summary>        protected uint ts_flush;        protected uint xmit;        /// <summary>        /// 是否启动无延迟模式        /// </summary>        protected uint nodelay;        /// <summary>        /// 是否调用过update函数的标识        /// </summary>        protected uint updated;        /// <summary>        /// 下次探查窗口的时间戳        /// </summary>        protected uint ts_probe;        /// <summary>        /// 探查窗口需要等待的时间        /// </summary>        protected uint probe_wait;        /// <summary>        /// 最大重传次数        /// </summary>        protected uint dead_link;        /// <summary>        /// 可发送的最大数据量        /// </summary>        protected uint incr;        /// <summary>        /// 触发快速重传的重复ack个数        /// </summary>        public int fastresend;        public int fastlimit;        /// <summary>        /// 取消拥塞控制        /// </summary>        protected int nocwnd;        protected int logmask;        /// <summary>        /// 是否采用流传输模式        /// </summary>        public int stream;        protected BufferOwner buffer;        #endregion        #region 锁和容器        /// <summary>        /// 增加锁保证发送线程安全,否则可能导致2个消息的分片交替入队。        /// <para/> 用例:普通发送和广播可能会导致多个线程同时调用Send方法。        /// </summary>        protected readonly object snd_queueLock = new object();        protected readonly object snd_bufLock = new object();        protected readonly object rcv_bufLock = new object();        protected readonly object rcv_queueLock = new object();        /// <summary>        /// 发送 ack 队列         /// </summary>        protected ConcurrentQueue<(uint sn, uint ts)> acklist = new ConcurrentQueue<(uint sn, uint ts)>();        /// <summary>        /// 发送等待队列        /// </summary>        internal ConcurrentQueue<Segment> snd_queue = new ConcurrentQueue<Segment>();        /// <summary>        /// 正在发送列表        /// </summary>        internal LinkedList<Segment> snd_buf = new LinkedList<Segment>();        /// <summary>        /// 正在等待触发接收回调函数消息列表        /// <para>需要执行的操作  添加 遍历 删除</para>        /// </summary>        internal List<Segment> rcv_queue = new List<Segment>();        /// <summary>        /// 正在等待重组消息列表        /// <para>需要执行的操作  添加 插入 遍历 删除</para>        /// </summary>        internal LinkedList<Segment> rcv_buf = new LinkedList<Segment>();        /// <summary>        /// get how many packet is waiting to be sent        /// </summary>        /// <returns></returns>        public int WaitSnd => snd_buf.Count + snd_queue.Count;        #endregion        #region IDisposable Support        private bool disposedValue = false; // 要检测冗余调用        /// <summary>        /// 是否正在释放        /// </summary>        private bool m_disposing = false;        protected bool CheckDispose()        {            if (m_disposing)            {                return true;            }            if (disposedValue)            {                throw new ObjectDisposedException(                    $"{nameof(Kcp)} [conv:{conv}]");            }            return false;        }        protected virtual void Dispose(bool disposing)        {            try            {                m_disposing = true;                if (!disposedValue)                {                    if (disposing)                    {                        // 释放托管状态(托管对象)。                        callbackHandle = null;                        acklist = null;                        buffer = null;                    }                    // 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。                    // 将大型字段设置为 null。                    void FreeCollection(IEnumerable<Segment> collection)                    {                        if (collection == null)                        {                            return;                        }                        foreach (var item in collection)                        {                            try                            {                                SegmentManager.Free(item);                            }                            catch (Exception)                            {                                //理论上此处不会有任何异常                                LogFail($"此处绝不应该出现异常。 Dispose 时出现预计外异常,联系作者");                            }                        }                    }                    lock (snd_queueLock)                    {                        while (snd_queue != null &&                               (snd_queue.TryDequeue(out var segment)                                || !snd_queue.IsEmpty)                        )                        {                            try                            {                                SegmentManager.Free(segment);                            }                            catch (Exception)                            {                                //理论上这里没有任何异常;                            }                        }                        snd_queue = null;                    }                    lock (snd_bufLock)                    {                        FreeCollection(snd_buf);                        snd_buf?.Clear();                        snd_buf = null;                    }                    lock (rcv_bufLock)                    {                        FreeCollection(rcv_buf);                        rcv_buf?.Clear();                        rcv_buf = null;                    }                    lock (rcv_queueLock)                    {                        FreeCollection(rcv_queue);                        rcv_queue?.Clear();                        rcv_queue = null;                    }                    disposedValue = true;                }            }            finally            {                m_disposing = false;            }        }        // 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。        ~KcpCore()        {            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。            Dispose(false);        }        // 添加此代码以正确实现可处置模式。        /// <summary>        /// 释放不是严格线程安全的,尽量使用和Update相同的线程调用,        /// 或者等待析构时自动释放。        /// </summary>        public void Dispose()        {            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。            Dispose(true);            // 如果在以上内容中替代了终结器,则取消注释以下行。            GC.SuppressFinalize(this);        }        #endregion        #region 功能逻辑        //功能函数        /// <summary>        /// Determine when should you invoke ikcp_update:        /// returns when you should invoke ikcp_update in millisec, if there        /// is no ikcp_input/_send calling. you can call ikcp_update in that        /// time, instead of call update repeatly.        /// <para></para>        /// Important to reduce unnacessary ikcp_update invoking. use it to        /// schedule ikcp_update (eg. implementing an epoll-like mechanism,        /// or optimize ikcp_update when handling massive kcp connections)        /// <para></para>        /// </summary>        /// <param name="time"></param>        /// <returns></returns>        public DateTimeOffset Check(in DateTimeOffset time)        {            if (CheckDispose())            {                //检查释放                return default;            }            if (updated == 0)            {                return time;            }            var current_ = time.ConvertTime();            var ts_flush_ = ts_flush;            var tm_flush_ = 0x7fffffff;            var tm_packet = 0x7fffffff;            var minimal = 0;            if (Itimediff(current_, ts_flush_) >= 10000 || Itimediff(current_, ts_flush_) < -10000)            {                ts_flush_ = current_;            }            if (Itimediff(current_, ts_flush_) >= 0)            {                return time;            }            tm_flush_ = Itimediff(ts_flush_, current_);            lock (snd_bufLock)            {                foreach (var seg in snd_buf)                {                    var diff = Itimediff(seg.resendts, current_);                    if (diff <= 0)                    {                        return time;                    }                    if (diff < tm_packet)                    {                        tm_packet = diff;                    }                }            }            minimal = tm_packet < tm_flush_ ? tm_packet : tm_flush_;            if (minimal >= interval) minimal = (int)interval;            return time + TimeSpan.FromMilliseconds(minimal);        }        /// <summary>        /// move available data from rcv_buf -> rcv_queue        /// </summary>        protected void Move_Rcv_buf_2_Rcv_queue()        {            lock (rcv_bufLock)            {                while (rcv_buf.Count > 0)                {                    var seg = rcv_buf.First.Value;                    if (seg.sn == rcv_nxt && rcv_queue.Count < rcv_wnd)                    {                        rcv_buf.RemoveFirst();                        lock (rcv_queueLock)                        {                            rcv_queue.Add(seg);                        }                        rcv_nxt++;                    }                    else                    {                        break;                    }                }            }        }        /// <summary>        /// update ack.        /// </summary>        /// <param name="rtt"></param>        protected void Update_ack(int rtt)        {            if (rx_srtt == 0)            {                rx_srtt = (uint)rtt;                rx_rttval = (uint)rtt / 2;            }            else            {                int delta = (int)((uint)rtt - rx_srtt);                if (delta < 0)                {                    delta = -delta;                }                rx_rttval = (3 * rx_rttval + (uint)delta) / 4;                rx_srtt = (uint)((7 * rx_srtt + rtt) / 8);                if (rx_srtt < 1)                {                    rx_srtt = 1;                }            }            var rto = rx_srtt + Max(interval, 4 * rx_rttval);            rx_rto = Ibound(rx_minrto, rto, IKCP_RTO_MAX);        }        protected void Shrink_buf()        {            lock (snd_bufLock)            {                snd_una = snd_buf.Count > 0 ? snd_buf.First.Value.sn : snd_nxt;            }        }        protected void Parse_ack(uint sn)        {            if (Itimediff(sn, snd_una) < 0 || Itimediff(sn, snd_nxt) >= 0)            {                return;            }            lock (snd_bufLock)            {                for (var p = snd_buf.First; p != null; p = p.Next)                {                    var seg = p.Value;                    if (sn == seg.sn)                    {                        snd_buf.Remove(p);                        SegmentManager.Free(seg);                        break;                    }                    if (Itimediff(sn, seg.sn) < 0)                    {                        break;                    }                }            }        }        protected void Parse_una(uint una)        {            /// 删除给定时间之前的片段。保留之后的片段            lock (snd_bufLock)            {                while (snd_buf.First != null)                {                    var seg = snd_buf.First.Value;                    if (Itimediff(una, seg.sn) > 0)                    {                        snd_buf.RemoveFirst();                        SegmentManager.Free(seg);                    }                    else                    {                        break;                    }                }            }        }        protected void Parse_fastack(uint sn, uint ts)        {            if (Itimediff(sn, snd_una) < 0 || Itimediff(sn, snd_nxt) >= 0)            {                return;            }            lock (snd_bufLock)            {                foreach (var item in snd_buf)                {                    var seg = item;                    if (Itimediff(sn, seg.sn) < 0)                    {                        break;                    }                    else if (sn != seg.sn)                    {#if !IKCP_FASTACK_CONSERVE                        seg.fastack++;#else                        if (Itimediff(ts, seg.ts) >= 0)                        {                            seg.fastack++;                        }#endif                    }                }            }        }        /// <summary>        /// 处理下层网络收到的数据包        /// </summary>        /// <param name="newseg"></param>        internal virtual void Parse_data(Segment newseg)        {            var sn = newseg.sn;            lock (rcv_bufLock)            {                if (Itimediff(sn, rcv_nxt + rcv_wnd) >= 0 || Itimediff(sn, rcv_nxt) < 0)                {                    // 如果接收到数据报文的编号大于 rcv_nxt + rcv_wnd 或小于 rcv_nxt, 这个报文就会被丢弃.                    SegmentManager.Free(newseg);                    return;                }                var repeat = false;                ///检查是否重复消息和插入位置                LinkedListNode<Segment> p;                for (p = rcv_buf.Last; p != null; p = p.Previous)                {                    var seg = p.Value;                    if (seg.sn == sn)                    {                        repeat = true;                        break;                    }                    if (Itimediff(sn, seg.sn) > 0)                    {                        break;                    }                }                if (!repeat)                {                    if (CanLog(KcpLogMask.IKCP_LOG_PARSE_DATA))                    {                        LogWriteLine($"{newseg.ToLogString()}", KcpLogMask.IKCP_LOG_PARSE_DATA.ToString());                    }                    if (p == null)                    {                        rcv_buf.AddFirst(newseg);                        if (newseg.frg + 1 > rcv_wnd)                        {                            //分片数大于接收窗口,造成kcp阻塞冻结。                            //Console.WriteLine($"分片数大于接收窗口,造成kcp阻塞冻结。frgCount:{newseg.frg + 1}  rcv_wnd:{rcv_wnd}");                            //百分之百阻塞冻结,打印日志没有必要。直接抛出异常。                            throw new NotSupportedException(                                $"分片数大于接收窗口,造成kcp阻塞冻结。frgCount:{newseg.frg + 1}  rcv_wnd:{rcv_wnd}");                        }                    }                    else                    {                        rcv_buf.AddAfter(p, newseg);                    }                }                else                {                    SegmentManager.Free(newseg);                }            }            Move_Rcv_buf_2_Rcv_queue();        }        protected ushort Wnd_unused()        {            ///此处没有加锁,所以不要内联变量,否则可能导致 判断变量和赋值变量不一致            int waitCount = rcv_queue.Count;            if (waitCount < rcv_wnd)            {                //Q:为什么要减去nrcv_que,rcv_queue中已经排好序了,还要算在接收窗口内,感觉不能理解?                //现在问题是如果一个超大数据包,分片数大于rcv_wnd接收窗口,会导致rcv_wnd持续为0,阻塞整个流程。                //个人理解,rcv_queue中的数据是已经确认的数据,无论用户是否recv,都不应该影响收发。                //A:现在在发送出加一个分片数检测,过大直接抛出异常。防止阻塞发送。                //在接收端也加一个检测,如果(frg+1)分片数 > rcv_wnd,也要抛出一个异常或者警告。至少有个提示。                /// fix https://github.com/skywind3000/kcp/issues/126                /// 实际上 rcv_wnd 不应该大于65535                var count = rcv_wnd - waitCount;                return (ushort)Min(count, ushort.MaxValue);            }            return 0;        }        /// <summary>        /// flush pending data        /// </summary>        protected void Flush()        {                      var current_ = current;            var buffer_ = buffer;            var change = 0;            var lost = 0;            var offset = 0;            if (updated == 0)            {                return;            }            ushort wnd_ = Wnd_unused();            unsafe            {                ///在栈上分配这个segment,这个segment随用随销毁,不会被保存                const int len = KcpSegment.LocalOffset + KcpSegment.HeadOffset;                var ptr = stackalloc byte[len];                KcpSegment seg = new KcpSegment(ptr, 0);                //seg = KcpSegment.AllocHGlobal(0);                seg.conv = conv;                seg.cmd = IKCP_CMD_ACK;                //seg.frg = 0;                seg.wnd = wnd_;                seg.una = rcv_nxt;                //seg.len = 0;                //seg.sn = 0;                //seg.ts = 0;                #region flush acknowledges                if (CheckDispose())                {                                        //检查释放                    return;                }                while (acklist.TryDequeue(out var temp))                {                    if (offset + IKCP_OVERHEAD > mtu)                    {                        callbackHandle.Output(buffer, offset);                        offset = 0;                        buffer = CreateBuffer(BufferNeedSize);                        //IKcpOutputer outputer = null;                        //var span = outputer.GetSpan(offset);                        //buffer.Memory.Span.Slice(0, offset).CopyTo(span);                        //outputer.Advance(offset);                        //outputer.Flush();                    }                    seg.sn = temp.sn;                    seg.ts = temp.ts;                    offset += seg.Encode(buffer.Memory.Span.Slice(offset));                }                #endregion                #region probe window size (if remote window size equals zero)                // probe window size (if remote window size equals zero)                if (rmt_wnd == 0)                {                    if (probe_wait == 0)                    {                        probe_wait = IKCP_PROBE_INIT;                        ts_probe = current + probe_wait;                    }                    else                    {                        if (Itimediff(current, ts_probe) >= 0)                        {                            if (probe_wait < IKCP_PROBE_INIT)                            {                                probe_wait = IKCP_PROBE_INIT;                            }                            probe_wait += probe_wait / 2;                            if (probe_wait > IKCP_PROBE_LIMIT)                            {                                probe_wait = IKCP_PROBE_LIMIT;                            }                            ts_probe = current + probe_wait;                            probe |= IKCP_ASK_SEND;                        }                    }                }                else                {                    ts_probe = 0;                    probe_wait = 0;                }                #endregion                #region flush window probing commands                // flush window probing commands                if ((probe & IKCP_ASK_SEND) != 0)                {                    seg.cmd = IKCP_CMD_WASK;                    if (offset + IKCP_OVERHEAD > (int)mtu)                    {                        callbackHandle.Output(buffer, offset);                        offset = 0;                        buffer = CreateBuffer(BufferNeedSize);                    }                    offset += seg.Encode(buffer.Memory.Span.Slice(offset));                }                if ((probe & IKCP_ASK_TELL) != 0)                {                    seg.cmd = IKCP_CMD_WINS;                    if (offset + IKCP_OVERHEAD > (int)mtu)                    {                        callbackHandle.Output(buffer, offset);                        offset = 0;                        buffer = CreateBuffer(BufferNeedSize);                    }                    offset += seg.Encode(buffer.Memory.Span.Slice(offset));                }                probe = 0;                #endregion            }            #region 刷新,将发送等待列表移动到发送列表            // calculate window size            var cwnd_ = Min(snd_wnd, rmt_wnd);            if (nocwnd == 0)            {                cwnd_ = Min(cwnd, cwnd_);            }            while (Itimediff(snd_nxt, snd_una + cwnd_) < 0)            {                if (snd_queue.TryDequeue(out var newseg))                {                    newseg.conv = conv;                    newseg.cmd = IKCP_CMD_PUSH;                    newseg.wnd = wnd_;                    newseg.ts = current_;                    newseg.sn = snd_nxt;                    snd_nxt++;                    newseg.una = rcv_nxt;                    newseg.resendts = current_;                    newseg.rto = rx_rto;                    newseg.fastack = 0;                    newseg.xmit = 0;                    lock (snd_bufLock)                    {                        snd_buf.AddLast(newseg);                    }                }                else                {                    break;                }            }            #endregion            #region 刷新 发送列表,调用Output            // calculate resent            var resent = fastresend > 0 ? (uint)fastresend : 0xffffffff;            var rtomin = nodelay == 0 ? (rx_rto >> 3) : 0;            lock (snd_bufLock)            {                // flush data segments                // if (snd_buf.Count > 0)                // {                //     LogTool.Log($"准备发送包数量{cwnd_}  {snd_buf.Count}  {snd_queue.Count}");                // }                              foreach (var item in snd_buf)                {                    var segment = item;                    var needsend = false;                    var debug = Itimediff(current_, segment.resendts);                    if (segment.xmit == 0)                    {                        //新加入 snd_buf 中, 从未发送过的报文直接发送出去;                        needsend = true;                        segment.xmit++;                        segment.rto = rx_rto;                                                // LogTool.Log($"新发送包{segment.sn} 大小{segment.len}"  );                        segment.resendts = current_ + rx_rto + rtomin;                    }                    else if (Itimediff(current_, segment.resendts) >= 0)                    {                        //发送过的, 但是在 RTO 内未收到 ACK 的报文, 需要重传;                        needsend = true;                        segment.xmit++;                        this.xmit++;                        if (nodelay == 0)                        {                            segment.rto += Math.Max(segment.rto, rx_rto);                        }                        else                        {                            var step = nodelay < 2 ? segment.rto : rx_rto;                            segment.rto += step / 2;                        }                        // LogTool.Log($"重送包{segment.sn} 大小{segment.len}  次数{segment.xmit}");                        segment.resendts = current_ + segment.rto;                        lost = 1;                    }                    else if (segment.fastack >= resent)                    {                        //发送过的, 但是 ACK 失序若干次的报文, 需要执行快速重传.                        // LogTool.Log($"快速重传{segment.sn} 大小{segment.len}  次数{segment.xmit}");                        if (segment.xmit <= fastlimit                            || fastlimit <= 0)                        {                            needsend = true;                            segment.xmit++;                            segment.fastack = 0;                            segment.resendts = current_ + segment.rto;                            change++;                        }                    }                    if (needsend)                    {                        segment.ts = current_;                        segment.wnd = wnd_;                        segment.una = rcv_nxt;                        var need = IKCP_OVERHEAD + segment.len;                        if (offset + need > mtu)                        {                            callbackHandle.Output(buffer, offset);                            offset = 0;                            buffer = CreateBuffer(BufferNeedSize);                        }                        offset += segment.Encode(buffer.Memory.Span.Slice(offset));                        if (CanLog(KcpLogMask.IKCP_LOG_NEED_SEND))                        {                            LogWriteLine($"{segment.ToLogString(true)}", KcpLogMask.IKCP_LOG_NEED_SEND.ToString());                        }                        if (segment.xmit >= dead_link)                        {                            state = -1;                            if (CanLog(KcpLogMask.IKCP_LOG_DEAD_LINK))                            {                                LogWriteLine($"state = -1; xmit:{segment.xmit} >= dead_link:{dead_link}",                                    KcpLogMask.IKCP_LOG_DEAD_LINK.ToString());                            }                        }                    }                }            }            // flash remain segments            if (offset > 0)            {                callbackHandle.Output(buffer, offset);                offset = 0;                buffer = CreateBuffer(BufferNeedSize);            }            #endregion            #region update ssthresh            // update ssthresh 根据丢包情况计算 ssthresh 和 cwnd.            if (change != 0)            {                var inflight = snd_nxt - snd_una;                ssthresh = inflight / 2;                if (ssthresh < IKCP_THRESH_MIN)                {                    ssthresh = IKCP_THRESH_MIN;                }                cwnd = ssthresh + resent;                incr = cwnd * mss;            }            if (lost != 0)            {                ssthresh = cwnd / 2;                if (ssthresh < IKCP_THRESH_MIN)                {                    ssthresh = IKCP_THRESH_MIN;                }                cwnd = 1;                incr = mss;            }            if (cwnd < 1)            {                cwnd = 1;                incr = mss;            }            #endregion            if (state == -1)            {                OnDeadlink();            }        }        protected virtual void OnDeadlink()        {        }        /// <summary>        /// Test OutputWriter        /// </summary>        protected void Flush2()        {            var current_ = current;            var change = 0;            var lost = 0;            if (updated == 0)            {                return;            }            ushort wnd_ = Wnd_unused();            unsafe            {                ///在栈上分配这个segment,这个segment随用随销毁,不会被保存                const int len = KcpSegment.LocalOffset + KcpSegment.HeadOffset;                var ptr = stackalloc byte[len];                KcpSegment seg = new KcpSegment(ptr, 0);                //seg = KcpSegment.AllocHGlobal(0);                seg.conv = conv;                seg.cmd = IKCP_CMD_ACK;                //seg.frg = 0;                seg.wnd = wnd_;                seg.una = rcv_nxt;                //seg.len = 0;                //seg.sn = 0;                //seg.ts = 0;                #region flush acknowledges                if (CheckDispose())                {                    //检查释放                    return;                }                while (acklist.TryDequeue(out var temp))                {                    if (OutputWriter.UnflushedBytes + IKCP_OVERHEAD > mtu)                    {                        OutputWriter.Flush();                    }                    seg.sn = temp.sn;                    seg.ts = temp.ts;                    seg.Encode(OutputWriter);                }                #endregion                #region probe window size (if remote window size equals zero)                // probe window size (if remote window size equals zero)                if (rmt_wnd == 0)                {                    if (probe_wait == 0)                    {                        probe_wait = IKCP_PROBE_INIT;                        ts_probe = current + probe_wait;                    }                    else                    {                        if (Itimediff(current, ts_probe) >= 0)                        {                            if (probe_wait < IKCP_PROBE_INIT)                            {                                probe_wait = IKCP_PROBE_INIT;                            }                            probe_wait += probe_wait / 2;                            if (probe_wait > IKCP_PROBE_LIMIT)                            {                                probe_wait = IKCP_PROBE_LIMIT;                            }                            ts_probe = current + probe_wait;                            probe |= IKCP_ASK_SEND;                        }                    }                }                else                {                    ts_probe = 0;                    probe_wait = 0;                }                #endregion                #region flush window probing commands                // flush window probing commands                if ((probe & IKCP_ASK_SEND) != 0)                {                    seg.cmd = IKCP_CMD_WASK;                    if (OutputWriter.UnflushedBytes + IKCP_OVERHEAD > (int)mtu)                    {                        OutputWriter.Flush();                    }                    seg.Encode(OutputWriter);                }                if ((probe & IKCP_ASK_TELL) != 0)                {                    seg.cmd = IKCP_CMD_WINS;                    if (OutputWriter.UnflushedBytes + IKCP_OVERHEAD > (int)mtu)                    {                        OutputWriter.Flush();                    }                    seg.Encode(OutputWriter);                }                probe = 0;                #endregion            }            #region 刷新,将发送等待列表移动到发送列表            // calculate window size            var cwnd_ = Min(snd_wnd, rmt_wnd);            if (nocwnd == 0)            {                cwnd_ = Min(cwnd, cwnd_);            }            while (Itimediff(snd_nxt, snd_una + cwnd_) < 0)            {                if (snd_queue.TryDequeue(out var newseg))                {                    newseg.conv = conv;                    newseg.cmd = IKCP_CMD_PUSH;                    newseg.wnd = wnd_;                    newseg.ts = current_;                    newseg.sn = snd_nxt;                    snd_nxt++;                    newseg.una = rcv_nxt;                    newseg.resendts = current_;                    newseg.rto = rx_rto;                    newseg.fastack = 0;                    newseg.xmit = 0;                    lock (snd_bufLock)                    {                        snd_buf.AddLast(newseg);                    }                }                else                {                    break;                }            }            #endregion            #region 刷新 发送列表,调用Output            // calculate resent            var resent = fastresend > 0 ? (uint)fastresend : 0xffffffff;            var rtomin = nodelay == 0 ? (rx_rto >> 3) : 0;            lock (snd_bufLock)            {                // flush data segments                foreach (var item in snd_buf)                {                    var segment = item;                    var needsend = false;                    var debug = Itimediff(current_, segment.resendts);                    if (segment.xmit == 0)                    {                        //新加入 snd_buf 中, 从未发送过的报文直接发送出去;                        needsend = true;                        segment.xmit++;                        segment.rto = rx_rto;                        segment.resendts = current_ + rx_rto + rtomin;                    }                    else if (Itimediff(current_, segment.resendts) >= 0)                    {                        //发送过的, 但是在 RTO 内未收到 ACK 的报文, 需要重传;                        needsend = true;                        segment.xmit++;                        this.xmit++;                        if (nodelay == 0)                        {                            segment.rto += Math.Max(segment.rto, rx_rto);                        }                        else                        {                            var step = nodelay < 2 ? segment.rto : rx_rto;                            segment.rto += step / 2;                        }                        segment.resendts = current_ + segment.rto;                        lost = 1;                    }                    else if (segment.fastack >= resent)                    {                        //发送过的, 但是 ACK 失序若干次的报文, 需要执行快速重传.                        if (segment.xmit <= fastlimit                            || fastlimit <= 0)                        {                            needsend = true;                            segment.xmit++;                            segment.fastack = 0;                            segment.resendts = current_ + segment.rto;                            change++;                        }                    }                    if (needsend)                    {                        segment.ts = current_;                        segment.wnd = wnd_;                        segment.una = rcv_nxt;                        var need = IKCP_OVERHEAD + segment.len;                        if (OutputWriter.UnflushedBytes + need > mtu)                        {                            OutputWriter.Flush();                        }                        segment.Encode(OutputWriter);                        if (CanLog(KcpLogMask.IKCP_LOG_NEED_SEND))                        {                            LogWriteLine($"{segment.ToLogString(true)}", KcpLogMask.IKCP_LOG_NEED_SEND.ToString());                        }                        if (segment.xmit >= dead_link)                        {                            state = -1;                            if (CanLog(KcpLogMask.IKCP_LOG_DEAD_LINK))                            {                                LogWriteLine($"state = -1; xmit:{segment.xmit} >= dead_link:{dead_link}",                                    KcpLogMask.IKCP_LOG_DEAD_LINK.ToString());                            }                        }                    }                }            }            // flash remain segments            if (OutputWriter.UnflushedBytes > 0)            {                OutputWriter.Flush();            }            #endregion            #region update ssthresh            // update ssthresh 根据丢包情况计算 ssthresh 和 cwnd.            if (change != 0)            {                var inflight = snd_nxt - snd_una;                ssthresh = inflight / 2;                if (ssthresh < IKCP_THRESH_MIN)                {                    ssthresh = IKCP_THRESH_MIN;                }                cwnd = ssthresh + resent;                incr = cwnd * mss;            }            if (lost != 0)            {                ssthresh = cwnd / 2;                if (ssthresh < IKCP_THRESH_MIN)                {                    ssthresh = IKCP_THRESH_MIN;                }                cwnd = 1;                incr = mss;            }            if (cwnd < 1)            {                cwnd = 1;                incr = mss;            }            #endregion            if (state == -1)            {                OnDeadlink();            }        }        /// <summary>        /// update state (call it repeatedly, every 10ms-100ms), or you can ask        /// ikcp_check when to call it again (without ikcp_input/_send calling).        /// </summary>        /// <param name="time">DateTime.UtcNow</param>        public void Update(in DateTimeOffset time)        {            if (CheckDispose())            {                //检查释放                return;            }            current = time.ConvertTime();            if (updated == 0)            {                updated = 1;                ts_flush = current;            }            var slap = Itimediff(current, ts_flush);            if (slap >= 10000 || slap < -10000)            {                ts_flush = current;                slap = 0;            }            if (slap >= 0)            {                ts_flush += interval;                if (Itimediff(current, ts_flush) >= 0)                {                    ts_flush = current + interval;                }                Flush();            }        }        #endregion        #region 设置控制        public int SetMtu(int mtu = IKCP_MTU_DEF)        {            if (mtu < 50 || mtu < IKCP_OVERHEAD)            {                return -1;            }            var buffer_ = CreateBuffer(BufferNeedSize);            if (null == buffer_)            {                return -2;            }            this.mtu = (uint)mtu;            mss = this.mtu - IKCP_OVERHEAD;            buffer.Dispose();            buffer = buffer_;            return 0;        }        /// <summary>        ///         /// </summary>        /// <param name="interval_"></param>        /// <returns></returns>        public int Interval(int interval_)        {            if (interval_ > 5000)            {                interval_ = 5000;            }            else if (interval_ < 0)            {                /// 将最小值 10 改为 0;                ///在特殊形况下允许CPU满负荷运转;                interval_ = 0;            }            interval = (uint)interval_;            return 0;        }        public int NoDelay(int nodelay_, int interval_, int resend_, int nc_)        {            if (nodelay_ > 0)            {                nodelay = (uint)nodelay_;                if (nodelay_ != 0)                {                    rx_minrto = IKCP_RTO_NDL;                }                else                {                    rx_minrto = IKCP_RTO_MIN;                }            }            if (resend_ >= 0)            {                fastresend = resend_;            }            if (nc_ >= 0)            {                nocwnd = nc_;            }            return Interval(interval_);        }        public int WndSize(int sndwnd = IKCP_WND_SND, int rcvwnd = IKCP_WND_RCV)        {            if (sndwnd > 0)            {                snd_wnd = (uint)sndwnd;            }            if (rcvwnd > 0)            {                rcv_wnd = (uint)rcvwnd;            }            return 0;        }        #endregion    }    public partial class KcpCore<Segment> : IKcpSendable    {        /// <summary>        /// user/upper level send, returns below zero for error        /// </summary>        /// <param name="span"></param>        /// <param name="options"></param>        /// <returns></returns>        public int Send(ReadOnlySpan<byte> span, object options = null)        {            if (CheckDispose())            {                //检查释放                return -4;            }            if (mss <= 0)            {                throw new InvalidOperationException($" mss <= 0 ");            }            if (span.Length == 0)            {                return -1;            }            var offset = 0;            int count;            #region append to previous segment in streaming mode (if possible)            /// 基于线程安全和数据结构的等原因,移除了追加数据到最后一个包行为。            #endregion            #region fragment            if (span.Length <= mss)            {                count = 1;            }            else            {                count = (int)(span.Length + mss - 1) / (int)mss;            }            if (count > IKCP_WND_RCV)            {                return -2;            }            if (count == 0)            {                count = 1;            }            lock (snd_queueLock)            {                for (var i = 0; i < count; i++)                {                    int size;                    if (span.Length - offset > mss)                    {                        size = (int)mss;                    }                    else                    {                        size = (int)span.Length - offset;                    }                    var seg = SegmentManager.Alloc(size);                    span.Slice(offset, size).CopyTo(seg.data);                    offset += size;                    seg.frg = (byte)(count - i - 1);                    snd_queue.Enqueue(seg);                }            }            #endregion            return 0;        }        //public int Send(Span<byte> span)        //{        //    return Send((ReadOnlySpan<byte>)span);        //}        public int Send(ReadOnlySequence<byte> span, object options = null)        {            if (CheckDispose())            {                //检查释放                return -4;            }            if (mss <= 0)            {                throw new InvalidOperationException($" mss <= 0 ");            }            if (span.Length == 0)            {                return -1;            }            var offset = 0;            int count;            #region append to previous segment in streaming mode (if possible)            /// 基于线程安全和数据结构的等原因,移除了追加数据到最后一个包行为。            #endregion            #region fragment            if (span.Length <= mss)            {                count = 1;            }            else            {                count = (int)(span.Length + mss - 1) / (int)mss;            }            if (count > IKCP_WND_RCV)            {                return -2;            }            if (count == 0)            {                count = 1;            }            lock (snd_queueLock)            {                for (var i = 0; i < count; i++)                {                    int size;                    if (span.Length - offset > mss)                    {                        size = (int)mss;                    }                    else                    {                        size = (int)span.Length - offset;                    }                    var seg = SegmentManager.Alloc(size);                    span.Slice(offset, size).CopyTo(seg.data);                    offset += size;                    seg.frg = (byte)(count - i - 1);                    snd_queue.Enqueue(seg);                }            }            #endregion            return 0;        }    }    public partial class KcpCore<Segment> : IKcpInputable    {        /// <summary>        /// when you received a low level packet (eg. UDP packet), call it        /// </summary>        /// <param name="span"></param>        /// <returns></returns>        public int Input(ReadOnlySpan<byte> span)        {            if (CheckDispose())            {                //检查释放                return -4;            }            if (CanLog(KcpLogMask.IKCP_LOG_INPUT))            {                LogWriteLine($"[RI] {span.Length} bytes", KcpLogMask.IKCP_LOG_INPUT.ToString());            }            if (span.Length < IKCP_OVERHEAD)            {                return -1;            }            uint prev_una = snd_una;            var offset = 0;            int flag = 0;            uint maxack = 0;            uint latest_ts = 0;            while (true)            {                uint ts = 0;                uint sn = 0;                uint length = 0;                uint una = 0;                uint conv_ = 0;                ushort wnd = 0;                byte cmd = 0;                byte frg = 0;                if (span.Length - offset < IKCP_OVERHEAD)                {                    break;                }                Span<byte> header = stackalloc byte[24];                span.Slice(offset, 24).CopyTo(header);                offset += ReadHeader(header,                    ref conv_,                    ref cmd,                    ref frg,                    ref wnd,                    ref ts,                    ref sn,                    ref una,                    ref length);                if (conv != conv_)                {                    return -1;                }                if (span.Length - offset < length || (int)length < 0)                {                    return -2;                }                switch (cmd)                {                    case IKCP_CMD_PUSH:                    case IKCP_CMD_ACK:                    case IKCP_CMD_WASK:                    case IKCP_CMD_WINS:                        break;                    default:                        return -3;                }                rmt_wnd = wnd;                Parse_una(una);                Shrink_buf();                if (IKCP_CMD_ACK == cmd)                {                    if (Itimediff(current, ts) >= 0)                    {                        Update_ack(Itimediff(current, ts));                    }                    Parse_ack(sn);                    Shrink_buf();                    if (flag == 0)                    {                        flag = 1;                        maxack = sn;                        latest_ts = ts;                    }                    else if (Itimediff(sn, maxack) > 0)                    {#if !IKCP_FASTACK_CONSERVE                        maxack = sn;                        latest_ts = ts;#else                        if (Itimediff(ts, latest_ts) > 0)                        {                            maxack = sn;                            latest_ts = ts;                        }#endif                    }                    if (CanLog(KcpLogMask.IKCP_LOG_IN_ACK))                    {                        LogWriteLine($"input ack: sn={sn} rtt={Itimediff(current, ts)} rto={rx_rto}",                            KcpLogMask.IKCP_LOG_IN_ACK.ToString());                    }                }                else if (IKCP_CMD_PUSH == cmd)                {                    if (CanLog(KcpLogMask.IKCP_LOG_IN_DATA))                    {                        LogWriteLine($"input psh: sn={sn} ts={ts}", KcpLogMask.IKCP_LOG_IN_DATA.ToString());                    }                    if (Itimediff(sn, rcv_nxt + rcv_wnd) < 0)                    {                        ///instead of ikcp_ack_push                        acklist.Enqueue((sn, ts));                        if (Itimediff(sn, rcv_nxt) >= 0)                        {                            var seg = SegmentManager.Alloc((int)length);                            seg.conv = conv_;                            seg.cmd = cmd;                            seg.frg = frg;                            seg.wnd = wnd;                            seg.ts = ts;                            seg.sn = sn;                            seg.una = una;                            //seg.len = length;  长度在分配时确定,不能改变                            if (length > 0)                            {                                span.Slice(offset, (int)length).CopyTo(seg.data);                            }                            // LogTool.Log($"收到包{sn}  {rcv_nxt}");                            Parse_data(seg);                        }                    }                }                else if (IKCP_CMD_WASK == cmd)                {                    // ready to send back IKCP_CMD_WINS in Ikcp_flush                    // tell remote my window size                    probe |= IKCP_ASK_TELL;                    if (CanLog(KcpLogMask.IKCP_LOG_IN_PROBE))                    {                        LogWriteLine($"input probe", KcpLogMask.IKCP_LOG_IN_PROBE.ToString());                    }                }                else if (IKCP_CMD_WINS == cmd)                {                    // do nothing                    if (CanLog(KcpLogMask.IKCP_LOG_IN_WINS))                    {                        LogWriteLine($"input wins: {wnd}", KcpLogMask.IKCP_LOG_IN_WINS.ToString());                    }                }                else                {                    return -3;                }                offset += (int)length;            }            if (flag != 0)            {                Parse_fastack(maxack, latest_ts);            }            if (Itimediff(this.snd_una, prev_una) > 0)            {                if (cwnd < rmt_wnd)                {                    if (cwnd < ssthresh)                    {                        cwnd++;                        incr += mss;                    }                    else                    {                        if (incr < mss)                        {                            incr = mss;                        }                        incr += (mss * mss) / incr + (mss / 16);                        if ((cwnd + 1) * mss <= incr)                        {#if true                            cwnd = (incr + mss - 1) / ((mss > 0) ? mss : 1);#else                            cwnd++;#endif                        }                    }                    if (cwnd > rmt_wnd)                    {                        cwnd = rmt_wnd;                        incr = rmt_wnd * mss;                    }                }            }            return 0;        }        /// <summary>        /// <inheritdoc cref="Input(ReadOnlySpan{byte})"/>        /// </summary>        /// <param name="span"></param>        /// <returns></returns>        public int Input(ReadOnlySequence<byte> span)        {            if (CheckDispose())            {                //检查释放                return -4;            }            if (CanLog(KcpLogMask.IKCP_LOG_INPUT))            {                LogWriteLine($"[RI] {span.Length} bytes", KcpLogMask.IKCP_LOG_INPUT.ToString());            }            if (span.Length < IKCP_OVERHEAD)            {                return -1;            }            uint prev_una = snd_una;            var offset = 0;            int flag = 0;            uint maxack = 0;            uint latest_ts = 0;            while (true)            {                uint ts = 0;                uint sn = 0;                uint length = 0;                uint una = 0;                uint conv_ = 0;                ushort wnd = 0;                byte cmd = 0;                byte frg = 0;                if (span.Length - offset < IKCP_OVERHEAD)                {                    break;                }                Span<byte> header = stackalloc byte[24];                span.Slice(offset, 24).CopyTo(header);                offset += ReadHeader(header,                    ref conv_,                    ref cmd,                    ref frg,                    ref wnd,                    ref ts,                    ref sn,                    ref una,                    ref length);                if (conv != conv_)                {                    return -1;                }                if (span.Length - offset < length || (int)length < 0)                {                    return -2;                }                switch (cmd)                {                    case IKCP_CMD_PUSH:                    case IKCP_CMD_ACK:                    case IKCP_CMD_WASK:                    case IKCP_CMD_WINS:                        break;                    default:                        return -3;                }                rmt_wnd = wnd;                Parse_una(una);                Shrink_buf();                if (IKCP_CMD_ACK == cmd)                {                    if (Itimediff(current, ts) >= 0)                    {                        Update_ack(Itimediff(current, ts));                    }                    Parse_ack(sn);                    Shrink_buf();                    if (flag == 0)                    {                        flag = 1;                        maxack = sn;                        latest_ts = ts;                    }                    else if (Itimediff(sn, maxack) > 0)                    {#if !IKCP_FASTACK_CONSERVE                        maxack = sn;                        latest_ts = ts;#else                        if (Itimediff(ts, latest_ts) > 0)                        {                            maxack = sn;                            latest_ts = ts;                        }#endif                    }                    if (CanLog(KcpLogMask.IKCP_LOG_IN_ACK))                    {                        LogWriteLine($"input ack: sn={sn} rtt={Itimediff(current, ts)} rto={rx_rto}",                            KcpLogMask.IKCP_LOG_IN_ACK.ToString());                    }                }                else if (IKCP_CMD_PUSH == cmd)                {                    if (CanLog(KcpLogMask.IKCP_LOG_IN_DATA))                    {                        LogWriteLine($"input psh: sn={sn} ts={ts}", KcpLogMask.IKCP_LOG_IN_DATA.ToString());                    }                    if (Itimediff(sn, rcv_nxt + rcv_wnd) < 0)                    {                        ///instead of ikcp_ack_push                        acklist.Enqueue((sn, ts));                        if (Itimediff(sn, rcv_nxt) >= 0)                        {                            var seg = SegmentManager.Alloc((int)length);                            seg.conv = conv_;                            seg.cmd = cmd;                            seg.frg = frg;                            seg.wnd = wnd;                            seg.ts = ts;                            seg.sn = sn;                            seg.una = una;                            //seg.len = length;  长度在分配时确定,不能改变                            if (length > 0)                            {                                span.Slice(offset, (int)length).CopyTo(seg.data);                            }                            Parse_data(seg);                        }                    }                }                else if (IKCP_CMD_WASK == cmd)                {                    // ready to send back IKCP_CMD_WINS in Ikcp_flush                    // tell remote my window size                    probe |= IKCP_ASK_TELL;                    if (CanLog(KcpLogMask.IKCP_LOG_IN_PROBE))                    {                        LogWriteLine($"input probe", KcpLogMask.IKCP_LOG_IN_PROBE.ToString());                    }                }                else if (IKCP_CMD_WINS == cmd)                {                    // do nothing                    if (CanLog(KcpLogMask.IKCP_LOG_IN_WINS))                    {                        LogWriteLine($"input wins: {wnd}", KcpLogMask.IKCP_LOG_IN_WINS.ToString());                    }                }                else                {                    return -3;                }                offset += (int)length;            }            if (flag != 0)            {                Parse_fastack(maxack, latest_ts);            }            if (Itimediff(this.snd_una, prev_una) > 0)            {                if (cwnd < rmt_wnd)                {                    if (cwnd < ssthresh)                    {                        cwnd++;                        incr += mss;                    }                    else                    {                        if (incr < mss)                        {                            incr = mss;                        }                        incr += (mss * mss) / incr + (mss / 16);                        if ((cwnd + 1) * mss <= incr)                        {#if true                            cwnd = (incr + mss - 1) / ((mss > 0) ? mss : 1);#else                            cwnd++;#endif                        }                    }                    if (cwnd > rmt_wnd)                    {                        cwnd = rmt_wnd;                        incr = rmt_wnd * mss;                    }                }            }            return 0;        }        public static int ReadHeader(ReadOnlySpan<byte> header,            ref uint conv_,            ref byte cmd,            ref byte frg,            ref ushort wnd,            ref uint ts,            ref uint sn,            ref uint una,            ref uint length)        {            var offset = 0;            if (IsLittleEndian)            {                conv_ = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(offset));                offset += 4;                cmd = header[offset];                offset += 1;                frg = header[offset];                offset += 1;                wnd = BinaryPrimitives.ReadUInt16LittleEndian(header.Slice(offset));                offset += 2;                ts = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(offset));                offset += 4;                sn = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(offset));                offset += 4;                una = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(offset));                offset += 4;                length = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(offset));                offset += 4;            }            else            {                conv_ = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(offset));                offset += 4;                cmd = header[offset];                offset += 1;                frg = header[offset];                offset += 1;                wnd = BinaryPrimitives.ReadUInt16BigEndian(header.Slice(offset));                offset += 2;                ts = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(offset));                offset += 4;                sn = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(offset));                offset += 4;                una = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(offset));                offset += 4;                length = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(offset));                offset += 4;            }            return offset;        }    }}
 |