Skip to content

Commit a7ec85a

Browse files
committed
[feat]网络层增加Byte[]和ArraySegment的发送重载,直达底层,这是用户最常用的方法,也是性能最好的路径。
1 parent d5a2116 commit a7ec85a

File tree

9 files changed

+266
-32
lines changed

9 files changed

+266
-32
lines changed

NewLife.Core/Data/IPacket.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public static String ToHex(this IPacket pk, Int32 maxLength = 32, String? separa
150150
return sb.Return(true);
151151
}
152152

153-
/// <summary>拷贝</summary>
153+
/// <summary>写入数据流,netfx中可能有二次拷贝</summary>
154154
/// <param name="pk"></param>
155155
/// <param name="stream"></param>
156156
public static void CopyTo(this IPacket pk, Stream stream)
@@ -162,6 +162,8 @@ public static void CopyTo(this IPacket pk, Stream stream)
162162
#else
163163
if (p is ArrayPacket ap)
164164
stream.Write(ap.Buffer, ap.Offset, ap.Length);
165+
else if (p.TryGetArray(out var segment))
166+
stream.Write(segment.Array!, segment.Offset, segment.Count);
165167
else
166168
stream.Write(p.GetMemory());
167169
#endif
@@ -202,7 +204,7 @@ public static Stream GetStream(this IPacket pk)
202204
return ms;
203205
}
204206

205-
/// <summary>返回数据段</summary>
207+
/// <summary>返回数据段,可能有拷贝</summary>
206208
/// <returns></returns>
207209
public static ArraySegment<Byte> ToSegment(this IPacket pk)
208210
{
@@ -215,7 +217,7 @@ public static ArraySegment<Byte> ToSegment(this IPacket pk)
215217
return new ArraySegment<Byte>(ms.Return(true));
216218
}
217219

218-
/// <summary>返回数据段集合</summary>
220+
/// <summary>返回数据段集合,可能有拷贝</summary>
219221
/// <returns></returns>
220222
public static IList<ArraySegment<Byte>> ToSegments(this IPacket pk)
221223
{

NewLife.Core/Net/INetSession.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ public interface INetSession : IDisposable2
5151
/// <param name="data">数据包</param>
5252
INetSession Send(IPacket data);
5353

54+
/// <summary>发送数据,直达网卡</summary>
55+
/// <param name="data">字节数组</param>
56+
/// <param name="offset">偏移</param>
57+
/// <param name="count">字节数</param>
58+
/// <returns></returns>
59+
INetSession Send(Byte[] data, Int32 offset = 0, Int32 count = -1);
60+
5461
/// <summary>发送数据,直达网卡</summary>
5562
/// <param name="data">数据包</param>
5663
/// <returns></returns>

NewLife.Core/Net/ISocketRemote.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ public interface ISocketRemote : ISocket, IExtend
2828
/// <returns>是否成功</returns>
2929
Int32 Send(IPacket data);
3030

31+
/// <summary>发送原始数据包</summary>
32+
/// <remarks>
33+
/// 目标地址由<seealso cref="Remote"/>决定
34+
/// </remarks>
35+
/// <param name="data">字节数组</param>
36+
/// <param name="offset">偏移</param>
37+
/// <param name="count">字节数</param>
38+
/// <returns>是否成功</returns>
39+
Int32 Send(Byte[] data, Int32 offset = 0, Int32 count = -1);
40+
41+
/// <summary>发送原始数据包</summary>
42+
/// <remarks>
43+
/// 目标地址由<seealso cref="Remote"/>决定
44+
/// </remarks>
45+
/// <param name="data">数据包</param>
46+
/// <returns>是否成功</returns>
47+
Int32 Send(ArraySegment<Byte> data);
48+
3149
/// <summary>发送原始数据包</summary>
3250
/// <remarks>
3351
/// 目标地址由<seealso cref="Remote"/>决定

NewLife.Core/Net/NetSession.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,20 @@ public virtual INetSession Send(IPacket data)
242242
return this;
243243
}
244244

245+
/// <summary>发送数据,直达网卡</summary>
246+
/// <param name="data">字节数组</param>
247+
/// <param name="offset">偏移</param>
248+
/// <param name="count">字节数</param>
249+
public virtual INetSession Send(Byte[] data, Int32 offset = 0, Int32 count = -1)
250+
{
251+
var ns = (this as INetSession).Host;
252+
using var span = ns?.Tracer?.NewSpan($"net:{ns.Name}:Send", data.ToHex(offset, count), count > 0 ? count : data.Length - offset);
253+
254+
Session.Send(data, offset, count);
255+
256+
return this;
257+
}
258+
245259
/// <summary>发送数据,直达网卡</summary>
246260
/// <param name="data">数据包</param>
247261
public virtual INetSession Send(ReadOnlySpan<Byte> data)

NewLife.Core/Net/SessionBase.cs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Concurrent;
1+
using System;
2+
using System.Collections.Concurrent;
23
using System.Diagnostics.CodeAnalysis;
34
using System.Net;
45
using System.Net.Sockets;
@@ -258,6 +259,48 @@ public Int32 Send(IPacket data)
258259
/// <returns>是否成功</returns>
259260
protected abstract Int32 OnSend(IPacket data);
260261

262+
/// <summary>直接发送数据包 Byte[]/Packet</summary>
263+
/// <remarks>
264+
/// 目标地址由<seealso cref="Remote"/>决定
265+
/// </remarks>
266+
/// <param name="data">字节数组</param>
267+
/// <param name="offset">偏移</param>
268+
/// <param name="count">字节数</param>
269+
/// <returns>是否成功</returns>
270+
public Int32 Send(Byte[] data, Int32 offset = 0, Int32 count = -1)
271+
{
272+
if (Disposed) throw new ObjectDisposedException(GetType().Name);
273+
if (!Open()) return -1;
274+
275+
#if NET6_0_OR_GREATER
276+
return OnSend(new ReadOnlySpan<Byte>(data, offset, count));
277+
#else
278+
return OnSend(new ArraySegment<Byte>(data, offset, count));
279+
#endif
280+
}
281+
282+
/// <summary>直接发送数据包 Byte[]/Packet</summary>
283+
/// <remarks>
284+
/// 目标地址由<seealso cref="Remote"/>决定
285+
/// </remarks>
286+
/// <param name="data">数据包</param>
287+
/// <returns>是否成功</returns>
288+
public Int32 Send(ArraySegment<Byte> data)
289+
{
290+
if (Disposed) throw new ObjectDisposedException(GetType().Name);
291+
if (!Open()) return -1;
292+
293+
return OnSend(data);
294+
}
295+
296+
/// <summary>发送数据</summary>
297+
/// <remarks>
298+
/// 目标地址由<seealso cref="Remote"/>决定
299+
/// </remarks>
300+
/// <param name="data">数据包</param>
301+
/// <returns>是否成功</returns>
302+
protected abstract Int32 OnSend(ArraySegment<Byte> data);
303+
261304
/// <summary>直接发送数据包 Byte[]/Packet</summary>
262305
/// <remarks>
263306
/// 目标地址由<seealso cref="Remote"/>决定

NewLife.Core/Net/TcpSession.cs

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -316,15 +316,14 @@ protected override Int32 OnSend(IPacket pk)
316316
{
317317
if (count == 0)
318318
rs = sock.Send(Pool.Empty);
319+
else if (pk.TryGetArray(out var segment))
320+
rs = sock.Send(segment.Array!, segment.Offset, segment.Count, SocketFlags.None);
319321
else if (pk.TryGetSpan(out var data))
320322
{
321323
#if NETCOREAPP || NETSTANDARD2_1
322324
rs = sock.Send(data);
323325
#else
324-
if (pk.TryGetArray(out var segment))
325-
rs = sock.Send(segment.Array!, segment.Offset, segment.Count, SocketFlags.None);
326-
else
327-
rs = sock.Send(data.ToArray(), data.Length, SocketFlags.None);
326+
rs = sock.Send(data.ToArray(), data.Length, SocketFlags.None);
328327
#endif
329328
}
330329
else
@@ -337,12 +336,10 @@ protected override Int32 OnSend(IPacket pk)
337336
else
338337
pk.CopyTo(_Stream);
339338
}
340-
341-
//// 检查返回值
342-
//if (rs != count) throw new NetException($"发送[{count:n0}]而成功[{rs:n0}]");
343339
}
344340
catch (Exception ex)
345341
{
342+
// 发生异常时,全量数据写入埋点
346343
span?.SetError(ex, pk);
347344

348345
if (!ex.IsDisposed())
@@ -351,11 +348,76 @@ protected override Int32 OnSend(IPacket pk)
351348

352349
// 发送异常可能是连接出了问题,需要关闭
353350
Close("SendError");
351+
}
352+
353+
return -1;
354+
}
355+
finally
356+
{
357+
if (gotLock) _spinLock.Exit();
358+
}
354359

355-
//// 异步重连
356-
//ThreadPoolX.QueueUserWorkItem(Reconnect);
360+
LastTime = DateTime.Now;
357361

358-
//if (ThrowException) throw;
362+
return rs;
363+
}
364+
365+
/// <summary>发送数据</summary>
366+
/// <remarks>
367+
/// 目标地址由<seealso cref="SessionBase.Remote"/>决定
368+
/// </remarks>
369+
/// <param name="data">数据包</param>
370+
/// <returns>是否成功</returns>
371+
protected override Int32 OnSend(ArraySegment<Byte> data)
372+
{
373+
var count = data.Count;
374+
var logCount = count > LogDataLength ? count : LogDataLength;
375+
376+
if (Log != null && Log.Enable && LogSend)
377+
WriteLog("Send [{0}]: {1}", count, data.Array.ToHex(data.Offset, logCount));
378+
379+
using var span = Tracer?.NewSpan($"net:{Name}:Send", count + "", count);
380+
381+
var rs = count;
382+
var sock = Client;
383+
if (sock == null) return -1;
384+
385+
var gotLock = false;
386+
try
387+
{
388+
// 修改发送缓冲区,读取SendBufferSize耗时很大
389+
if (_bsize == 0) _bsize = sock.SendBufferSize;
390+
if (_bsize < count) sock.SendBufferSize = _bsize = count;
391+
392+
// 加锁发送
393+
_spinLock.Enter(ref gotLock);
394+
395+
if (_Stream == null)
396+
{
397+
if (count == 0)
398+
rs = sock.Send(Pool.Empty);
399+
else
400+
rs = sock.Send(data.Array!, data.Offset, data.Count, SocketFlags.None);
401+
}
402+
else
403+
{
404+
if (count == 0)
405+
_Stream.Write([]);
406+
else
407+
_Stream.Write(data.Array!, data.Offset, data.Count);
408+
}
409+
}
410+
catch (Exception ex)
411+
{
412+
// 发生异常时,全量数据写入埋点
413+
span?.SetError(ex, data.Array.ToHex(data.Offset, data.Count));
414+
415+
if (!ex.IsDisposed())
416+
{
417+
OnError("Send", ex);
418+
419+
// 发送异常可能是连接出了问题,需要关闭
420+
Close("SendError");
359421
}
360422

361423
return -1;
@@ -423,7 +485,8 @@ protected override Int32 OnSend(ReadOnlySpan<Byte> data)
423485
}
424486
catch (Exception ex)
425487
{
426-
span?.SetError(ex, data.ToHex(LogDataLength));
488+
// 发生异常时,全量数据写入埋点
489+
span?.SetError(ex, data.ToHex());
427490

428491
if (!ex.IsDisposed())
429492
{

0 commit comments

Comments
 (0)