diff --git a/.github/workflows/publish-beta.yml b/.github/workflows/publish-beta.yml
index ed2808e18..4eeed0347 100644
--- a/.github/workflows/publish-beta.yml
+++ b/.github/workflows/publish-beta.yml
@@ -2,11 +2,11 @@ name: publish-beta
on:
push:
- branches: [ master, dev, v10 ]
+ branches: [ master, dev ]
paths:
- 'NewLife.Core/**'
pull_request:
- branches: [ master, dev, v10 ]
+ branches: [ master, dev ]
paths:
- 'NewLife.Core/**'
workflow_dispatch:
diff --git a/NewLife.Core/Data/DbTable.cs b/NewLife.Core/Data/DbTable.cs
index 33e897132..d672bf99c 100644
--- a/NewLife.Core/Data/DbTable.cs
+++ b/NewLife.Core/Data/DbTable.cs
@@ -415,6 +415,8 @@ public void WriteData(Binary bn, Int32[] fields)
///
public IPacket ToPacket()
{
+ // 不确定所需大小,只能使用内存流,再包装为数据包。
+ // 头部预留8个字节,方便网络传输时添加协议头。
var ms = new MemoryStream
{
Position = 8
@@ -423,6 +425,8 @@ public IPacket ToPacket()
Write(ms);
ms.Position = 8;
+
+ // 包装为数据包,直接窃取内存流内部的缓冲区
return new ArrayPacket(ms);
}
diff --git a/NewLife.Core/Data/IPacket.cs b/NewLife.Core/Data/IPacket.cs
index 34b8d335f..64be95159 100644
--- a/NewLife.Core/Data/IPacket.cs
+++ b/NewLife.Core/Data/IPacket.cs
@@ -50,6 +50,13 @@ public interface IPacket
IPacket Slice(Int32 offset, Int32 count = -1);
}
+/// 拥有管理权的数据包。使用完以后需要释放
+public interface IOwnerPacket : IPacket, IDisposable
+{
+ /// 是否拥有管理权
+ Boolean HasOwner { get; set; }
+}
+
/// 内存包辅助类
public static class PacketHelper
{
@@ -247,7 +254,7 @@ public static Byte[] ReadBytes(this IPacket pk, Int32 offset = 0, Int32 count =
///
/// 使用时务必明确所有权归属,用完后及时释放。
///
-public struct OwnerPacket : IDisposable, IPacket
+public struct OwnerPacket : IDisposable, IPacket, IOwnerPacket
{
#region 属性
private IMemoryOwner _owner;
@@ -427,7 +434,7 @@ public IPacket Slice(Int32 offset, Int32 count)
}
/// 字节数组包
-public struct ArrayPacket : IDisposable, IPacket
+public struct ArrayPacket : IDisposable, IPacket, IOwnerPacket
{
#region 属性
private Byte[] _buffer;
@@ -455,6 +462,9 @@ public struct ArrayPacket : IDisposable, IPacket
/// 总长度
public Int32 Total => Length + (Next?.Total ?? 0);
+
+ /// 空数组
+ public static ArrayPacket Empty = new([]);
#endregion
#region 索引
@@ -504,6 +514,7 @@ public Byte this[Int32 index]
}
#endregion
+ #region 构造
/// 通过指定字节数组来实例化数据包
///
///
@@ -563,11 +574,8 @@ public ArrayPacket(Stream stream)
#endif
}
- //Set(stream.ToArray());
-
var buf = new Byte[stream.Length - stream.Position];
var count = stream.Read(buf, 0, buf.Length);
- //Set(buf, 0, count);
_buffer = buf;
_offset = 0;
_length = count;
@@ -587,6 +595,7 @@ public void Dispose()
HasOwner = false;
}
}
+ #endregion
/// 获取分片包。在管理权生命周期内短暂使用
///
@@ -603,16 +612,18 @@ public void Dispose()
///
/// 偏移
/// 个数。默认-1表示到末尾
- public IPacket Slice(Int32 offset, Int32 count)
- {
- //var remain = _length - offset;
- //if (count < 0 || count > remain) count = remain;
- //if (offset == 0 && count == _length) return this;
+ public ArrayPacket Slice(Int32 offset, Int32 count) => (ArrayPacket)(this as IPacket).Slice(offset, count);
- //var pk = new ArrayPacket(_buffer, _offset + offset, count) { HasOwner = HasOwner };
- //HasOwner = false;
-
- //return pk;
+ /// 切片得到新数据包,同时转移内存管理权,当前数据包应尽快停止使用
+ ///
+ /// 可能是引用同一块内存,也可能是新的内存。
+ /// 可能就是当前数据包,也可能引用相同的所有者或数组。
+ ///
+ /// 偏移
+ /// 个数。默认-1表示到末尾
+ IPacket IPacket.Slice(Int32 offset, Int32 count)
+ {
+ if (count == 0) return Empty;
IPacket? pk = null;
var start = Offset + offset;
@@ -645,8 +656,12 @@ public IPacket Slice(Int32 offset, Int32 count)
pk = new ArrayPacket(_buffer, start, remain) { Next = Next.Slice(0, count - remain) };
}
- if (pk is ArrayPacket ap) ap.HasOwner = HasOwner;
- HasOwner = false;
+ // 所有权转移
+ if (pk is ArrayPacket ap && ap._buffer == _buffer)
+ {
+ ap.HasOwner = HasOwner;
+ HasOwner = false;
+ }
return pk;
}
diff --git a/NewLife.Core/Http/HttpBase.cs b/NewLife.Core/Http/HttpBase.cs
index b70af12ba..181b61790 100644
--- a/NewLife.Core/Http/HttpBase.cs
+++ b/NewLife.Core/Http/HttpBase.cs
@@ -6,7 +6,7 @@
namespace NewLife.Http;
/// Http请求响应基类
-public abstract class HttpBase
+public abstract class HttpBase : IDisposable
{
#region 属性
/// 协议版本
@@ -36,6 +36,11 @@ public abstract class HttpBase
public String this[String key] { get => Headers[key] + ""; set => Headers[key] = value; }
#endregion
+ #region 构造
+ /// 释放
+ public void Dispose() => Body.TryDispose();
+ #endregion
+
#region 解析
/// 快速验证协议头,剔除非HTTP协议。仅排除,验证通过不一定就是HTTP协议
///
@@ -50,7 +55,7 @@ public static Boolean FastValidHeader(ReadOnlySpan data)
private static readonly Byte[] NewLine = [(Byte)'\r', (Byte)'\n'];
private static readonly Byte[] NewLine2 = [(Byte)'\r', (Byte)'\n', (Byte)'\r', (Byte)'\n'];
- /// 分析请求头
+ /// 分析请求头。截取Body时获取缓冲区所有权
///
///
public Boolean Parse(IPacket pk)
@@ -90,7 +95,7 @@ public Boolean Parse(IPacket pk)
//var str = pk.ReadBytes(0, p).ToStr();
- // 截取
+ // 截取主体,获取所有权
//var lines = str.Split("\r\n");
Body = pk.Slice(p + 4);
@@ -118,14 +123,17 @@ public Boolean Parse(IPacket pk)
#region 读写
/// 创建请求响应包
+ /// 数据来自缓冲池,使用者用完返回数据包后应该释放,以便把缓冲区放回池里
///
- public virtual IPacket Build()
+ public virtual IOwnerPacket Build()
{
var body = Body;
var len = body != null ? body.Total : 0;
var header = BuildHeader(len);
- var pk = new ArrayPacket(Encoding.UTF8.GetByteCount(header) + len);
+
+ // 从内存池申请缓冲区,Slice后管理权转移,外部使用完以后释放
+ using var pk = new ArrayPacket(Encoding.UTF8.GetByteCount(header) + len);
var writer = new SpanWriter(pk.GetSpan());
//BuildHeader(writer, len);
diff --git a/NewLife.Core/Http/HttpResponse.cs b/NewLife.Core/Http/HttpResponse.cs
index 9799ca840..66a0841c7 100644
--- a/NewLife.Core/Http/HttpResponse.cs
+++ b/NewLife.Core/Http/HttpResponse.cs
@@ -43,7 +43,7 @@ protected override Boolean OnParse(String firstLine)
/// 创建请求响应包
///
- public override IPacket Build()
+ public override IOwnerPacket Build()
{
// 如果响应异常,则使用响应描述作为内容
if (StatusCode > HttpStatusCode.OK && Body == null && !StatusDescription.IsNullOrEmpty())
diff --git a/NewLife.Core/Http/HttpSession.cs b/NewLife.Core/Http/HttpSession.cs
index 2f904c0fe..48531a9d6 100644
--- a/NewLife.Core/Http/HttpSession.cs
+++ b/NewLife.Core/Http/HttpSession.cs
@@ -81,8 +81,10 @@ public void Process(IData data)
if (req.ContentLength > MaxRequestLength)
{
var rs = new HttpResponse { StatusCode = HttpStatusCode.RequestEntityTooLarge };
- _session.Send(rs.Build());
+ // 发送响应。用完后释放数据包,还给缓冲池
+ using var res = rs.Build();
+ _session.Send(res);
_session.Dispose();
return;
@@ -91,6 +93,10 @@ public void Process(IData data)
_cache = new MemoryStream(req.ContentLength);
req.Body?.CopyTo(_cache);
//req.Body = req.Body.Clone();
+
+ // 请求主体数据来自缓冲区,要还回去
+ req.Body.TryDispose();
+ req.Body = null;
}
}
else if (req != null)
@@ -130,11 +136,20 @@ public void Process(IData data)
var closing = !req.KeepAlive && _websocket == null;
if (closing && !rs.Headers.ContainsKey("Connection")) rs.Headers["Connection"] = "close";
- _session.Send(rs.Build());
+ // 发送响应。用完后释放数据包,还给缓冲池
+ using var res = rs.Build();
+ _session.Send(res);
if (closing) _session.Dispose();
}
}
+
+ // 请求主体数据来自缓冲区,要还回去
+ if (req != null)
+ {
+ req.Body.TryDispose();
+ req.Body = null;
+ }
}
/// 收到新的Http请求,只有头部
diff --git a/NewLife.Core/Http/TinyHttpClient.cs b/NewLife.Core/Http/TinyHttpClient.cs
index 1a5f12c00..b0c0236be 100644
--- a/NewLife.Core/Http/TinyHttpClient.cs
+++ b/NewLife.Core/Http/TinyHttpClient.cs
@@ -127,7 +127,7 @@ protected virtual async Task GetStreamAsync(Uri? uri)
///
///
///
- protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
+ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
{
var ns = await GetStreamAsync(uri).ConfigureAwait(false);
@@ -135,7 +135,7 @@ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
if (request != null) await request.CopyToAsync(ns).ConfigureAwait(false);
// 接收
- var pk = new ArrayPacket(BufferSize);
+ using var pk = new ArrayPacket(BufferSize);
using var source = new CancellationTokenSource(Timeout);
#if NETCOREAPP || NETSTANDARD2_1
@@ -162,11 +162,11 @@ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
while (retry-- > 0)
{
// 发出请求
- rs = await SendDataAsync(uri, req).ConfigureAwait(false);
- if (rs == null || rs.Length == 0) return null;
+ using var rs2 = await SendDataAsync(uri, req).ConfigureAwait(false);
+ if (rs2 == null || rs2.Length == 0) return null;
// 解析响应
- if (!res.Parse(rs)) return res;
+ if (!res.Parse(rs2)) return res;
rs = res.Body;
// 跳转
@@ -181,6 +181,8 @@ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
uri = uri2;
request.RequestUri = uri;
+
+ req.TryDispose();
req = request.Build();
continue;
@@ -190,6 +192,9 @@ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
break;
}
+ // 释放数据包,还给缓冲池
+ req.TryDispose();
+
if (res.StatusCode != HttpStatusCode.OK) throw new Exception($"{(Int32)res.StatusCode} {res.StatusDescription}");
// 如果没有收完数据包
@@ -199,6 +204,7 @@ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
var last = rs;
while (total < res.ContentLength)
{
+ //todo 这里的IPacket.Append可能有问题,因为last本质上是结构体
var pk = await SendDataAsync(null, null).ConfigureAwait(false);
last.Append(pk);
@@ -212,7 +218,10 @@ protected virtual async Task SendDataAsync(Uri? uri, IPacket? request)
{
// 如果不足则读取一个chunk,因为有可能第一个响应包只有头部
if (rs.Length == 0)
+ {
+ rs.TryDispose();
rs = await SendDataAsync(null, null).ConfigureAwait(false);
+ }
res.Body = await ReadChunkAsync(rs);
}
@@ -285,6 +294,8 @@ protected virtual async Task ReadChunkAsync(IPacket body)
if (pk == null || pk.Length == 0) break;
if (pk.Length > 0) continue;
+ pk.TryDispose();
+
// 读取新的数据片段,如果不存在则跳出
pk = await SendDataAsync(null, null).ConfigureAwait(false);
if (pk == null || pk.Length == 0) break;
diff --git a/NewLife.Core/Http/WebSocket.cs b/NewLife.Core/Http/WebSocket.cs
index e0764b243..d3394c933 100644
--- a/NewLife.Core/Http/WebSocket.cs
+++ b/NewLife.Core/Http/WebSocket.cs
@@ -66,7 +66,7 @@ public class WebSocket
///
public void Process(IPacket pk)
{
- var message = new WebSocketMessage();
+ using var message = new WebSocketMessage();
if (message.Read(pk))
{
ActiveTime = DateTime.Now;
@@ -110,7 +110,7 @@ private void Send(WebSocketMessage msg)
var socket = Context?.Socket;
if (session == null && socket == null) throw new ObjectDisposedException(nameof(Context));
- var data = msg.ToPacket();
+ using var data = msg.ToPacket();
if (session != null)
session.Send(data);
else
@@ -138,7 +138,7 @@ public void SendAll(IPacket data, WebSocketMessageType type, FuncWebSocket消息
-public class WebSocketMessage
+public class WebSocketMessage : IDisposable
{
#region 属性
/// 消息是否结束
@@ -50,6 +50,11 @@ public class WebSocketMessage
public String? StatusDescription { get; set; }
#endregion
+ #region 构造
+ /// 销毁。回收数据包到内存池
+ public void Dispose() => Payload.TryDispose();
+ #endregion
+
#region 方法
/// 读取消息
///
@@ -123,7 +128,7 @@ public Boolean Read(IPacket pk)
/// 把消息转为封包
///
- public virtual IPacket ToPacket()
+ public virtual IOwnerPacket ToPacket()
{
var pk = Payload;
var len = pk == null ? 0 : pk.Length;
@@ -207,7 +212,7 @@ public virtual IPacket ToPacket()
if (!StatusDescription.IsNullOrEmpty()) writer.Write(StatusDescription);
}
- return rs.Slice(0, writer.Position);
+ return (rs.Slice(0, writer.Position) as IOwnerPacket)!;
}
#endregion
}
\ No newline at end of file
diff --git a/NewLife.Core/Net/Handlers/LengthFieldCodec.cs b/NewLife.Core/Net/Handlers/LengthFieldCodec.cs
index a54ce6768..4b30d04d1 100644
--- a/NewLife.Core/Net/Handlers/LengthFieldCodec.cs
+++ b/NewLife.Core/Net/Handlers/LengthFieldCodec.cs
@@ -34,7 +34,8 @@ protected override Object Encode(IHandlerContext context, IPacket msg)
// 尝试退格,直接利用缓冲区
if (msg is ArrayPacket ap && ap.Offset >= len)
{
- msg = new ArrayPacket(ap.Buffer, ap.Offset - len, ap.Length + len) { Next = ap.Next };
+ // 向下传递时,不要转移所有权。向上传递到较高层级才需要转移所有权。
+ msg = new ArrayPacket(ap.Buffer, ap.Offset - len, ap.Length + len) { Next = ap.Next/*, HasOwner = ap.HasOwner*/ };
}
else
{
diff --git a/NewLife.Core/Net/Handlers/WebSocketCodec.cs b/NewLife.Core/Net/Handlers/WebSocketCodec.cs
index 5f7551a10..2b2d9c4a7 100644
--- a/NewLife.Core/Net/Handlers/WebSocketCodec.cs
+++ b/NewLife.Core/Net/Handlers/WebSocketCodec.cs
@@ -56,7 +56,15 @@ public override Boolean Close(IHandlerContext context, String reason)
}
}
- return base.Read(context, message);
+ try
+ {
+ return base.Read(context, message);
+ }
+ finally
+ {
+ // 下游可能忘了释放内存,这里兜底释放
+ message.TryDispose();
+ }
}
/// 发送消息时,写入数据
@@ -71,6 +79,14 @@ public override Boolean Close(IHandlerContext context, String reason)
if (message is WebSocketMessage msg)
message = msg.ToPacket();
- return base.Write(context, message);
+ try
+ {
+ return base.Write(context, message);
+ }
+ finally
+ {
+ // 下游可能忘了释放内存,这里兜底释放
+ message.TryDispose();
+ }
}
}
diff --git a/NewLife.Core/Net/ISocketRemote.cs b/NewLife.Core/Net/ISocketRemote.cs
index f7165465d..bdb7f9e4b 100644
--- a/NewLife.Core/Net/ISocketRemote.cs
+++ b/NewLife.Core/Net/ISocketRemote.cs
@@ -32,11 +32,11 @@ public interface ISocketRemote : ISocket, IExtend
#region 接收
/// 接收数据。阻塞当前线程等待返回
///
- IPacket? Receive();
+ IOwnerPacket? Receive();
/// 异步接收数据
///
- Task ReceiveAsync(CancellationToken cancellationToken = default);
+ Task ReceiveAsync(CancellationToken cancellationToken = default);
/// 数据到达事件
event EventHandler Received;
@@ -133,7 +133,7 @@ public static Int32 Send(this ISocketRemote session, String msg, Encoding? encod
///
public static String ReceiveString(this ISocketRemote session, Encoding? encoding = null)
{
- var pk = session.Receive();
+ using var pk = session.Receive();
if (pk == null || pk.Length == 0) return String.Empty;
return pk.ToStr(encoding ?? Encoding.UTF8);
diff --git a/NewLife.Core/Net/ITransport.cs b/NewLife.Core/Net/ITransport.cs
index ce31caa13..bdbb93722 100644
--- a/NewLife.Core/Net/ITransport.cs
+++ b/NewLife.Core/Net/ITransport.cs
@@ -21,7 +21,7 @@ public interface ITransport : IDisposable
/// 读取数据
///
- IPacket? Receive();
+ IOwnerPacket? Receive();
/// 数据到达事件
event EventHandler Received;
diff --git a/NewLife.Core/Net/SessionBase.cs b/NewLife.Core/Net/SessionBase.cs
index 1601e5ac9..f5a3ad14d 100644
--- a/NewLife.Core/Net/SessionBase.cs
+++ b/NewLife.Core/Net/SessionBase.cs
@@ -262,7 +262,7 @@ public Int32 Send(IPacket data)
/// 接收数据
///
- public virtual IPacket? Receive()
+ public virtual IOwnerPacket? Receive()
{
if (Disposed) throw new ObjectDisposedException(GetType().Name);
@@ -271,7 +271,7 @@ public Int32 Send(IPacket data)
using var span = Tracer?.NewSpan($"net:{Name}:Receive", BufferSize + "");
try
{
- var pk = new ArrayPacket(BufferSize);
+ using var pk = new ArrayPacket(BufferSize);
var size = Client.Receive(pk.Buffer, SocketFlags.None);
if (span != null) span.Value = size;
@@ -286,7 +286,7 @@ public Int32 Send(IPacket data)
/// 异步接收数据
///
- public virtual async Task ReceiveAsync(CancellationToken cancellationToken = default)
+ public virtual async Task ReceiveAsync(CancellationToken cancellationToken = default)
{
if (Disposed) throw new ObjectDisposedException(GetType().Name);
@@ -295,7 +295,7 @@ public Int32 Send(IPacket data)
using var span = Tracer?.NewSpan($"net:{Name}:ReceiveAsync", BufferSize + "");
try
{
- var pk = new ArrayPacket(BufferSize);
+ using var pk = new ArrayPacket(BufferSize);
#if NETFRAMEWORK || NETSTANDARD2_0
var ar = Client.BeginReceive(pk.Buffer, 0, pk.Length, SocketFlags.None, null, Client);
var size = ar.IsCompleted ?
diff --git a/NewLife.Core/Net/TcpSession.cs b/NewLife.Core/Net/TcpSession.cs
index 6362c8c58..1f78ed5bf 100644
--- a/NewLife.Core/Net/TcpSession.cs
+++ b/NewLife.Core/Net/TcpSession.cs
@@ -378,7 +378,7 @@ protected override Int32 OnSend(IPacket pk)
#region 接收
/// 异步接收数据。重载以支持SSL
///
- public override async Task ReceiveAsync(CancellationToken cancellationToken = default)
+ public override async Task ReceiveAsync(CancellationToken cancellationToken = default)
{
if (!Open() || Client == null) return null;
@@ -388,7 +388,7 @@ protected override Int32 OnSend(IPacket pk)
using var span = Tracer?.NewSpan($"net:{Name}:ReceiveAsync", BufferSize + "");
try
{
- var pk = new ArrayPacket(BufferSize);
+ using var pk = new ArrayPacket(BufferSize);
var size = await ss.ReadAsync(pk.Buffer, 0, pk.Length, cancellationToken);
if (span != null) span.Value = size;
diff --git a/NewLife.Core/Net/UdpSession.cs b/NewLife.Core/Net/UdpSession.cs
index 33b84a3a8..fb78ae137 100644
--- a/NewLife.Core/Net/UdpSession.cs
+++ b/NewLife.Core/Net/UdpSession.cs
@@ -247,7 +247,7 @@ void TrySetCanceled(Object? state)
#region 接收
/// 接收数据
///
- public IPacket Receive()
+ public IOwnerPacket Receive()
{
if (Disposed) throw new ObjectDisposedException(GetType().Name);
if (Server?.Client == null) throw new InvalidOperationException(nameof(Server));
@@ -256,7 +256,7 @@ public IPacket Receive()
try
{
var ep = Remote.EndPoint as EndPoint;
- var pk = new ArrayPacket(Server.BufferSize);
+ using var pk = new ArrayPacket(Server.BufferSize);
var size = Server.Client.ReceiveFrom(pk.Buffer, ref ep);
if (span != null) span.Value = size;
@@ -271,7 +271,7 @@ public IPacket Receive()
/// 异步接收数据
///
- public virtual async Task ReceiveAsync(CancellationToken cancellationToken = default)
+ public virtual async Task ReceiveAsync(CancellationToken cancellationToken = default)
{
if (Disposed) throw new ObjectDisposedException(GetType().Name);
if (Server?.Client == null) throw new InvalidOperationException(nameof(Server));
@@ -280,7 +280,7 @@ public IPacket Receive()
try
{
var ep = Remote.EndPoint as EndPoint;
- var pk = new ArrayPacket(Server.BufferSize);
+ using var pk = new ArrayPacket(Server.BufferSize);
var socket = Server.Client;
#if NETFRAMEWORK || NETSTANDARD2_0
var ar = socket.BeginReceiveFrom(pk.Buffer, 0, pk.Length, SocketFlags.None, ref ep, null, socket);
diff --git a/NewLife.Core/Net/WebSocketClient.cs b/NewLife.Core/Net/WebSocketClient.cs
index 9eab522f4..446b145c5 100644
--- a/NewLife.Core/Net/WebSocketClient.cs
+++ b/NewLife.Core/Net/WebSocketClient.cs
@@ -105,7 +105,7 @@ public void SetRequestHeader(String headerName, String? headerValue)
///
public virtual async Task ReceiveMessageAsync(CancellationToken cancellationToken = default)
{
- var rs = await base.ReceiveAsync(cancellationToken);
+ using var rs = await base.ReceiveAsync(cancellationToken);
if (rs == null) return null;
var msg = new WebSocketMessage();
@@ -233,16 +233,18 @@ public static Boolean Handshake(ISocketClient client, Uri uri)
using var span = client.Tracer?.NewSpan($"net:{client.Name}:WebSocket", uri + "");
try
{
- // 发送请求
- var req = request.Build();
- client.Send(req);
+ // 发送请求。用完后释放数据包,还给缓冲池
+ {
+ using var req = request.Build();
+ client.Send(req);
+ }
// 接收响应
- var rs = client.Receive();
+ using var rs = client.Receive();
if (rs == null || rs.Length == 0) return false;
// 解析响应
- var res = new HttpResponse();
+ using var res = new HttpResponse();
if (!res.Parse(rs)) return false;
//if (res.StatusCode != HttpStatusCode.OK) throw new Exception($"{(Int32)res.StatusCode} {res.StatusDescription}");
diff --git a/NewLife.Core/Serialization/Binary/Binary.cs b/NewLife.Core/Serialization/Binary/Binary.cs
index 0e2753f5f..1729baaf4 100644
--- a/NewLife.Core/Serialization/Binary/Binary.cs
+++ b/NewLife.Core/Serialization/Binary/Binary.cs
@@ -544,6 +544,8 @@ public static IPacket FastWrite(Object value, Boolean encodeInt = true)
//return new ArrayPacket(buf, 8, buf.Length - 8);
bn.Stream.Position = 8;
+
+ // 包装为数据包,直接窃取内存流内部的缓冲区
return new ArrayPacket(bn.Stream);
}
diff --git a/NewLife.Core/Serialization/Interface/IAccessor.cs b/NewLife.Core/Serialization/Interface/IAccessor.cs
index b4d21b8a6..fbab08fb0 100644
--- a/NewLife.Core/Serialization/Interface/IAccessor.cs
+++ b/NewLife.Core/Serialization/Interface/IAccessor.cs
@@ -44,10 +44,12 @@ public static class AccessorHelper
///
public static IPacket ToPacket(this IAccessor accessor, Object? context = null)
{
- var ms = new MemoryStream();
+ var ms = new MemoryStream { Position = 8 };
accessor.Write(ms, context);
- ms.Position = 0;
+ ms.Position = 8;
+
+ // 包装为数据包,直接窃取内存流内部的缓冲区
return new ArrayPacket(ms);
}
diff --git a/NewLife.Core/Serialization/Interface/IFormatterX.cs b/NewLife.Core/Serialization/Interface/IFormatterX.cs
index 001a149c8..aa7cad19e 100644
--- a/NewLife.Core/Serialization/Interface/IFormatterX.cs
+++ b/NewLife.Core/Serialization/Interface/IFormatterX.cs
@@ -130,6 +130,8 @@ public Byte[] GetBytes()
public IPacket GetPacket()
{
Stream.Position = 0;
+
+ // 包装为数据包,直接窃取内存流内部的缓冲区
return new ArrayPacket(Stream);
}
#endregion
diff --git a/Samples/Zero.HttpServer/ClientTest.cs b/Samples/Zero.HttpServer/ClientTest.cs
index 980c4b3ce..4e2788974 100644
--- a/Samples/Zero.HttpServer/ClientTest.cs
+++ b/Samples/Zero.HttpServer/ClientTest.cs
@@ -77,7 +77,7 @@ public static async Task WebSocketClientTest()
await client.SendTextAsync("Hello NewLife");
- var rs = await client.ReceiveMessageAsync(default);
+ using var rs = await client.ReceiveMessageAsync(default);
client.WriteLog(rs.Payload.ToStr());
await Task.Delay(6_000);
@@ -86,8 +86,8 @@ public static async Task WebSocketClientTest()
await client.CloseAsync(1000, "通信完成", default);
client.WriteLog("Close");
- rs = await client.ReceiveMessageAsync(default);
- client.WriteLog("Close [{0}] {1}", rs.CloseStatus, rs.StatusDescription);
+ using var rs2 = await client.ReceiveMessageAsync(default);
+ client.WriteLog("Close [{0}] {1}", rs2.CloseStatus, rs2.StatusDescription);
client.Dispose();
}
diff --git a/Samples/Zero.Server/ClientTest.cs b/Samples/Zero.Server/ClientTest.cs
index a99732111..b3d375fc0 100644
--- a/Samples/Zero.Server/ClientTest.cs
+++ b/Samples/Zero.Server/ClientTest.cs
@@ -87,7 +87,7 @@ public static async void TcpSessionTest()
if (client is TcpSession tcp) tcp.MaxAsync = 0;
// 接收服务端握手。内部自动建立连接
- var rs = await client.ReceiveAsync(default);
+ using var rs = await client.ReceiveAsync(default);
client.WriteLog("<={0}", rs.ToStr());
// 发送数据
@@ -96,8 +96,8 @@ public static async void TcpSessionTest()
client.Send(str);
// 接收数据
- rs = await client.ReceiveAsync(default);
- client.WriteLog("<={0}", rs.ToStr());
+ using var rs2 = await client.ReceiveAsync(default);
+ client.WriteLog("<={0}", rs2.ToStr());
// 关闭连接
client.Close("测试完成");
@@ -123,12 +123,12 @@ public static async void UdpSessionTest()
client.Send(str);
// 接收服务端握手
- var rs = await client.ReceiveAsync(default);
+ using var rs = await client.ReceiveAsync(default);
client.WriteLog("<={0}", rs.ToStr());
// 接收数据
- rs = await client.ReceiveAsync(default);
- client.WriteLog("<={0}", rs.ToStr());
+ using var rs2 = await client.ReceiveAsync(default);
+ client.WriteLog("<={0}", rs2.ToStr());
// 关闭连接
client.Close("测试完成");