SegManager.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. using System.Buffers.Binary;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Runtime.InteropServices;
  5. namespace System.Net.Sockets.Kcp
  6. {
  7. /// <summary>
  8. /// 动态申请非托管内存
  9. /// </summary>
  10. public class SimpleSegManager : ISegmentManager<KcpSegment>
  11. {
  12. public static SimpleSegManager Default { get; } = new SimpleSegManager();
  13. public KcpSegment Alloc(int appendDateSize)
  14. {
  15. return KcpSegment.AllocHGlobal(appendDateSize);
  16. }
  17. public void Free(KcpSegment seg)
  18. {
  19. KcpSegment.FreeHGlobal(seg);
  20. }
  21. public class Kcp : Kcp<KcpSegment>
  22. {
  23. public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
  24. : base(conv_, callback, rentable)
  25. {
  26. SegmentManager = Default;
  27. }
  28. }
  29. public class KcpIO : KcpIO<KcpSegment>
  30. {
  31. public KcpIO(uint conv_)
  32. : base(conv_)
  33. {
  34. SegmentManager = Default;
  35. }
  36. }
  37. }
  38. /// <summary>
  39. /// 申请固定大小非托管内存。使用这个就不能SetMtu了,大小已经写死。
  40. /// </summary>
  41. /// <remarks>需要大量测试</remarks>
  42. public unsafe class UnSafeSegManager : ISegmentManager<KcpSegment>
  43. {
  44. /// <summary>
  45. /// 因为默认mtu是1400,并且内存需要内存行/内存页对齐。这里直接512对齐。
  46. /// </summary>
  47. public const int blockSize = 512 * 3;
  48. public readonly object locker = new object();
  49. public Stack<IntPtr> blocks = new Stack<IntPtr>();
  50. public HashSet<IntPtr> header = new HashSet<IntPtr>();
  51. public UnSafeSegManager()
  52. {
  53. Alloc();
  54. }
  55. public static UnSafeSegManager Default { get; } = new UnSafeSegManager();
  56. public KcpSegment Alloc(int appendDateSize)
  57. {
  58. lock (locker)
  59. {
  60. var total = KcpSegment.LocalOffset + KcpSegment.HeadOffset + appendDateSize;
  61. if (total > blockSize)
  62. {
  63. throw new ArgumentOutOfRangeException();
  64. }
  65. if (blocks.Count > 0)
  66. {
  67. }
  68. else
  69. {
  70. Alloc();
  71. }
  72. var ptr = blocks.Pop();
  73. Span<byte> span = new Span<byte>(ptr.ToPointer(), blockSize);
  74. span.Clear();
  75. return new KcpSegment((byte*)ptr.ToPointer(), (uint)appendDateSize);
  76. }
  77. }
  78. public void Free(KcpSegment seg)
  79. {
  80. IntPtr ptr = (IntPtr)seg.ptr;
  81. blocks.Push(ptr);
  82. }
  83. void Alloc()
  84. {
  85. int count = 50;
  86. IntPtr intPtr = Marshal.AllocHGlobal(blockSize * count);
  87. header.Add(intPtr);
  88. for (int i = 0; i < count; i++)
  89. {
  90. blocks.Push(intPtr + blockSize * i);
  91. }
  92. }
  93. ~UnSafeSegManager()
  94. {
  95. foreach (var item in header)
  96. {
  97. Marshal.FreeHGlobal(item);
  98. }
  99. }
  100. public class Kcp : Kcp<KcpSegment>
  101. {
  102. public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
  103. : base(conv_, callback, rentable)
  104. {
  105. SegmentManager = Default;
  106. }
  107. }
  108. public class KcpIO : KcpIO<KcpSegment>
  109. {
  110. public KcpIO(uint conv_)
  111. : base(conv_)
  112. {
  113. SegmentManager = Default;
  114. }
  115. }
  116. }
  117. /// <summary>
  118. /// 使用内存池,而不是非托管内存,有内存alloc,但是不多。可以解决Marshal.AllocHGlobal 内核调用带来的性能问题
  119. /// </summary>
  120. public class PoolSegManager : ISegmentManager<PoolSegManager.Seg>
  121. {
  122. /// <summary>
  123. /// 因为默认mtu是1400,并且内存需要内存行/内存页对齐。这里直接512对齐。
  124. /// </summary>
  125. public const int blockSize = 512 * 3;
  126. ConcurrentStack<Seg> Pool = new ConcurrentStack<Seg>();
  127. public static PoolSegManager Default { get; } = new PoolSegManager();
  128. public Seg Alloc(int appendDateSize)
  129. {
  130. if (appendDateSize > blockSize)
  131. {
  132. throw new NotSupportedException();
  133. }
  134. if (Pool.TryPop(out var ret))
  135. {
  136. }
  137. else
  138. {
  139. ret = new Seg(blockSize);
  140. }
  141. ret.len = (uint)appendDateSize;
  142. return ret;
  143. }
  144. public void Free(Seg seg)
  145. {
  146. seg.cmd = 0;
  147. seg.conv = 0;
  148. seg.fastack = 0;
  149. seg.frg = 0;
  150. seg.len = 0;
  151. seg.resendts = 0;
  152. seg.rto = 0;
  153. seg.sn = 0;
  154. seg.ts = 0;
  155. seg.una = 0;
  156. seg.wnd = 0;
  157. seg.xmit = 0;
  158. Pool.Push(seg);
  159. }
  160. public class Seg : IKcpSegment
  161. {
  162. ///以下为需要网络传输的参数
  163. public const int LocalOffset = 4 * 4;
  164. public const int HeadOffset = Kcp.IKCP_OVERHEAD;
  165. byte[] cache;
  166. public Seg(int blockSize)
  167. {
  168. cache = Buffers.ArrayPool<byte>.Shared.Rent(blockSize);
  169. }
  170. public byte cmd { get; set; }
  171. public uint conv { get; set; }
  172. public Span<byte> data => cache.AsSpan().Slice(0, (int)len);
  173. public uint fastack { get; set; }
  174. public byte frg { get; set; }
  175. public uint len { get; internal set; }
  176. public uint resendts { get; set; }
  177. public uint rto { get; set; }
  178. public uint sn { get; set; }
  179. public uint ts { get; set; }
  180. public uint una { get; set; }
  181. public ushort wnd { get; set; }
  182. public uint xmit { get; set; }
  183. public int Encode(Span<byte> buffer)
  184. {
  185. var datelen = (int)(HeadOffset + len);
  186. ///备用偏移值 现阶段没有使用
  187. const int offset = 0;
  188. if (BitConverter.IsLittleEndian)
  189. {
  190. BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset), conv);
  191. buffer[offset + 4] = cmd;
  192. buffer[offset + 5] = frg;
  193. BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(offset + 6), wnd);
  194. BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 8), ts);
  195. BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 12), sn);
  196. BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 16), una);
  197. BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset + 20), len);
  198. data.CopyTo(buffer.Slice(HeadOffset));
  199. }
  200. else
  201. {
  202. BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset), conv);
  203. buffer[offset + 4] = cmd;
  204. buffer[offset + 5] = frg;
  205. BinaryPrimitives.WriteUInt16BigEndian(buffer.Slice(offset + 6), wnd);
  206. BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 8), ts);
  207. BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 12), sn);
  208. BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 16), una);
  209. BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset + 20), len);
  210. data.CopyTo(buffer.Slice(HeadOffset));
  211. }
  212. return datelen;
  213. }
  214. }
  215. public class Kcp : Kcp<Seg>
  216. {
  217. public Kcp(uint conv_, IKcpCallback callback, IRentable rentable = null)
  218. : base(conv_, callback, rentable)
  219. {
  220. SegmentManager = Default;
  221. }
  222. }
  223. public class KcpIO : KcpIO<Seg>
  224. {
  225. public KcpIO(uint conv_)
  226. : base(conv_)
  227. {
  228. SegmentManager = Default;
  229. }
  230. }
  231. }
  232. }