BITFALL/Assets/BITKit/UnityPluginsSupport/KumoKyaku/Kcp/SegManager.cs

269 lines
8.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Buffers.Binary;
namespace System.Net.Sockets.Kcp
{
/// <summary>
/// 动态申请非托管内存
/// </summary>
public class SimpleSegManager : ISegmentManager<KcpSegment>
{
public static SimpleSegManager Default { get; } = new SimpleSegManager();
public KcpSegment Alloc(int appendDateSize)
{
return KcpSegment.AllocHGlobal(appendDateSize);
}
public void Free(KcpSegment seg)
{
KcpSegment.FreeHGlobal(seg);
}
public class Kcp : Kcp<KcpSegment>
{
public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
: base(conv_, callback, rentable)
{
SegmentManager = Default;
}
}
public class KcpIO : KcpIO<KcpSegment>
{
public KcpIO(uint conv_)
: base(conv_)
{
SegmentManager = Default;
}
}
}
/// <summary>
/// 申请固定大小非托管内存。使用这个就不能SetMtu了大小已经写死。
/// </summary>
/// <remarks>需要大量测试</remarks>
public unsafe class UnSafeSegManager : ISegmentManager<KcpSegment>
{
public static UnSafeSegManager Default { get; } = new UnSafeSegManager();
/// <summary>
/// 因为默认mtu是1400并且内存需要内存行/内存页对齐。这里直接512对齐。
/// </summary>
public const int blockSize = 512 * 3;
public HashSet<IntPtr> header = new HashSet<IntPtr>();
public Stack<IntPtr> blocks = new Stack<IntPtr>();
public readonly object locker = new object();
public UnSafeSegManager()
{
Alloc();
}
void Alloc()
{
int count = 50;
IntPtr intPtr = Marshal.AllocHGlobal(blockSize * count);
header.Add(intPtr);
for (int i = 0; i < count; i++)
{
blocks.Push(intPtr + blockSize * i);
}
}
~UnSafeSegManager()
{
foreach (var item in header)
{
Marshal.FreeHGlobal(item);
}
}
public KcpSegment Alloc(int appendDateSize)
{
lock (locker)
{
var total = KcpSegment.LocalOffset + KcpSegment.HeadOffset + appendDateSize;
if (total > blockSize)
{
throw new ArgumentOutOfRangeException();
}
if (blocks.Count > 0)
{
}
else
{
Alloc();
}
var ptr = blocks.Pop();
Span<byte> span = new Span<byte>(ptr.ToPointer(), blockSize);
span.Clear();
return new KcpSegment((byte*)ptr.ToPointer(), (uint)appendDateSize);
}
}
public void Free(KcpSegment seg)
{
lock (locker)
{
IntPtr ptr = (IntPtr)seg.ptr;
blocks.Push(ptr);
}
}
public class Kcp : Kcp<KcpSegment>
{
public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
: base(conv_, callback, rentable)
{
SegmentManager = Default;
}
}
public class KcpIO : KcpIO<KcpSegment>
{
public KcpIO(uint conv_)
: base(conv_)
{
SegmentManager = Default;
}
}
}
/// <summary>
/// 使用内存池而不是非托管内存有内存alloc但是不多。可以解决Marshal.AllocHGlobal 内核调用带来的性能问题
/// </summary>
public class PoolSegManager : ISegmentManager<PoolSegManager.Seg>
{
public static PoolSegManager Default { get; } = new PoolSegManager();
/// <summary>
/// 因为默认mtu是1400并且内存需要内存行/内存页对齐。这里直接512对齐。
/// </summary>
public const int blockSize = 512 * 3;
public class Seg : IKcpSegment
{
byte[] cache;
public Seg(int blockSize)
{
cache = Buffers.ArrayPool<byte>.Shared.Rent(blockSize);
}
///以下为需要网络传输的参数
public const int LocalOffset = 4 * 4;
public const int HeadOffset = Kcp.IKCP_OVERHEAD;
public byte cmd { get; set; }
public uint conv { get; set; }
public Span<byte> data => cache.AsSpan().Slice(0, (int)len);
public uint fastack { get; set; }
public byte frg { get; set; }
public uint len { get; internal set; }
public uint resendts { get; set; }
public uint rto { get; set; }
public uint sn { get; set; }
public uint ts { get; set; }
public uint una { get; set; }
public ushort wnd { get; set; }
public uint xmit { get; set; }
public int Encode(Span<byte> buffer)
{
var datelen = (int)(HeadOffset + len);
///备用偏移值 现阶段没有使用
const int offset = 0;
if (BitConverter.IsLittleEndian)
{
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset), conv);
buffer[offset + 4] = cmd;
buffer[offset + 5] = frg;
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(offset + 6), wnd);
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 8), ts);
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 12), sn);
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 16), una);
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 20), len);
data.CopyTo(buffer.Slice(HeadOffset));
}
else
{
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset), conv);
buffer[offset + 4] = cmd;
buffer[offset + 5] = frg;
BinaryPrimitives.WriteUInt16BigEndian(buffer.Slice(offset + 6), wnd);
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 8), ts);
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 12), sn);
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 16), una);
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 20), len);
data.CopyTo(buffer.Slice(HeadOffset));
}
return datelen;
}
}
ConcurrentStack<Seg> Pool = new ConcurrentStack<Seg>();
public Seg Alloc(int appendDateSize)
{
if (appendDateSize > blockSize)
{
throw new NotSupportedException();
}
if (Pool.TryPop(out var ret))
{
}
else
{
ret = new Seg(blockSize);
}
ret.len = (uint)appendDateSize;
return ret;
}
public void Free(Seg seg)
{
seg.cmd = 0;
seg.conv = 0;
seg.fastack = 0;
seg.frg = 0;
seg.len = 0;
seg.resendts = 0;
seg.rto = 0;
seg.sn = 0;
seg.ts = 0;
seg.una = 0;
seg.wnd = 0;
seg.xmit = 0;
Pool.Push(seg);
}
public class Kcp : Kcp<Seg>
{
public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
: base(conv_, callback, rentable)
{
SegmentManager = Default;
}
}
public class KcpIO : KcpIO<Seg>
{
public KcpIO(uint conv_)
: base(conv_)
{
SegmentManager = Default;
}
}
}
}