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 = 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 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 = 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) { 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); }