/// <summary> /// 释放非托管内存 /// </summary> /// <param name="seg"></param> public static void FreeHGlobal(KcpSegment seg) { unsafe { Marshal.FreeHGlobal((IntPtr)seg.ptr); } }
private static void WriteRecv(IBufferWriter <byte> writer, KcpSegment seg) { var curCount = (int)seg.len; var target = writer.GetSpan(curCount); seg.data.CopyTo(target); KcpSegment.FreeHGlobal(seg); writer.Advance(curCount); }
/// <summary> /// 这个函数不检查任何参数 /// </summary> /// <param name="buffer"></param> /// <returns></returns> int UncheckRecv(Span <byte> buffer) { var recover = false; if (rcv_queue.Count >= rcv_wnd) { recover = true; } #region merge fragment. /// merge fragment. var recvLength = 0; lock (rcv_queueLock) { var count = 0; foreach (var seg in rcv_queue) { seg.data.CopyTo(buffer.Slice(recvLength)); recvLength += (int)seg.len; count++; int frg = seg.frg; KcpSegment.FreeHGlobal(seg); if (frg == 0) { break; } } if (count > 0) { rcv_queue.RemoveRange(0, count); } } #endregion Move_Rcv_buf_2_Rcv_queue(); #region fast recover /// fast recover if (rcv_queue.Count < rcv_wnd && recover) { // ready to send back IKCP_CMD_WINS in ikcp_flush // tell remote my window size probe |= IKCP_ASK_TELL; } #endregion return(recvLength); }
// Modified by Insthync // 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 // 将大型字段设置为 null。 private void Dispose_FreeCollection(IEnumerable <KcpSegment> collection) { if (collection == null) { return; } foreach (var item in collection) { try { KcpSegment.FreeHGlobal(item); } catch (Exception) { //理论上此处不会有任何异常 } } }
public int Send(ReadOnlySequence <byte> span, object option = 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; } 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 = KcpSegment.AllocHGlobal(size); span.Slice(offset, size).CopyTo(seg.data); offset += size; seg.frg = (byte)(count - i - 1); snd_queue.Enqueue(seg); } #endregion return(0); }
internal override void Parse_data(KcpSegment newseg) { base.Parse_data(newseg); FastChechRecv(); }
public int Input(ReadOnlySpan <byte> data) { if (CheckDispose()) { //检查释放 return(-4); } uint temp_una = snd_una; if (data.Length < IKCP_OVERHEAD) { return(-1); } var offset = 0; int flag = 0; uint maxack = 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 (data.Length - offset < IKCP_OVERHEAD) { break; } if (IsLittleEndian) { conv_ = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); offset += 4; if (conv != conv_) { return(-1); } cmd = data[offset]; offset += 1; frg = data[offset]; offset += 1; wnd = BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(offset)); offset += 2; ts = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); offset += 4; sn = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); offset += 4; una = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); offset += 4; length = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); offset += 4; } else { conv_ = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset)); offset += 4; if (conv != conv_) { return(-1); } cmd = data[offset]; offset += 1; frg = data[offset]; offset += 1; wnd = BinaryPrimitives.ReadUInt16BigEndian(data.Slice(offset)); offset += 2; ts = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset)); offset += 4; sn = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset)); offset += 4; una = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset)); offset += 4; length = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset)); offset += 4; } if (data.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; } else if (Itimediff(sn, maxack) > 0) { maxack = sn; } } else if (IKCP_CMD_PUSH == cmd) { 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 = KcpSegment.AllocHGlobal((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) { data.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; } else if (IKCP_CMD_WINS == cmd) { // do nothing } else { return(-3); } offset += (int)length; } if (flag != 0) { Parse_fastack(maxack); } if (Itimediff(this.snd_una, temp_una) > 0) { if (cwnd < rmt_wnd) { var mss_ = mss; if (cwnd < ssthresh) { cwnd++; incr += mss_; } else { if (incr < mss_) { incr = mss_; } incr += (mss_ * mss_) / incr + (mss_ / 16); if ((cwnd + 1) * mss_ <= incr) { cwnd++; } } if (cwnd > rmt_wnd) { cwnd = rmt_wnd; incr = rmt_wnd * mss_; } } } return(0); }
// Modified by Insthync protected virtual void Dispose(bool disposing) { try { m_disposing = true; if (!disposedValue) { if (disposing) { // 释放托管状态(托管对象)。 callbackHandle = null; acklist = null; buffer = null; } KcpSegment segment; while (snd_queue != null && (snd_queue.TryDequeue(out segment) || !snd_queue.IsEmpty) ) { try { KcpSegment.FreeHGlobal(segment); } catch (Exception) { //理论上这里没有任何异常; } } snd_queue = null; lock (snd_bufLock) { Dispose_FreeCollection(snd_buf); snd_buf?.Clear(); snd_buf = null; } lock (rcv_bufLock) { Dispose_FreeCollection(rcv_buf); rcv_buf?.Clear(); rcv_buf = null; } lock (rcv_queueLock) { Dispose_FreeCollection(rcv_queue); rcv_queue?.Clear(); rcv_queue = null; } disposedValue = true; } } finally { m_disposing = false; } }