From f2cab6da6f1f6ece800ec2c3555f5038be31a799 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:06:20 +0000 Subject: [PATCH 1/2] Initial plan From 7f6ae0a84b903da58ce97015fd0c1111826c61be Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:14:00 +0000 Subject: [PATCH 2/2] Downgrade WebSocket normal-disconnect exceptions from Error to Debug When a WebSocket connection closes normally (server restart, network jitter, client close), exceptions such as ObjectDisposedException, SocketException (ConnectionReset/ConnectionAborted/OperationAborted) and WebSocketException (ConnectionClosedPrematurely / Aborted state) are expected and should not flood the log at ERROR level. Changes: - WsChannel.cs: Add ObjectDisposedException silent break, add IsNormalDisconnect helper, downgrade normal SocketException codes (ConnectionReset 10054, ConnectionAborted 10053, OperationAborted 995) to Debug log in DoPull receive loop. - WsChannelCore.cs: Same ObjectDisposedException and SocketException handling; additionally catch WebSocketException with ConnectionClosedPrematurely or Aborted socket state and downgrade to Debug, simplifying the redundant state check in the generic handler. Fixes NewLifeX/NewLife.Remoting# --- NewLife.Remoting/Clients/WsChannel.cs | 14 ++++++++++++++ NewLife.Remoting/Clients/WsChannelCore.cs | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/NewLife.Remoting/Clients/WsChannel.cs b/NewLife.Remoting/Clients/WsChannel.cs index 0cfba6e..0ef59fd 100644 --- a/NewLife.Remoting/Clients/WsChannel.cs +++ b/NewLife.Remoting/Clients/WsChannel.cs @@ -154,6 +154,12 @@ private async Task DoPull(WebSocketClient socket, CancellationTokenSource source catch (ThreadInterruptedException) { break; } catch (TaskCanceledException) { } catch (OperationCanceledException) { } + catch (ObjectDisposedException) { break; } + catch (SocketException sex) when (IsNormalDisconnect(sex.SocketErrorCode)) + { + _client.Log?.Debug("[{0}]WebSocket连接断开[{1}]", _client.Name, sex.SocketErrorCode); + break; + } catch (Exception ex) { if (source.IsCancellationRequested) break; @@ -199,6 +205,14 @@ protected virtual async Task OnReceive(IPacket data, CancellationToken cancellat await _client.HandleAsync(data, ctx, cancellationToken).ConfigureAwait(false); } + /// 判断是否为正常断开的SocketError,这类错误降级为Debug日志 + /// Socket错误码 + /// 是否为正常断开 + protected static Boolean IsNormalDisconnect(SocketError socketError) => + socketError is SocketError.ConnectionReset // 10054 - 对方重置连接 + or SocketError.ConnectionAborted // 10053 - 连接被中止 + or SocketError.OperationAborted; // 995 - 操作被中止(本地socket关闭时) + /// 发送文本消息 /// 数据包 /// 取消令牌 diff --git a/NewLife.Remoting/Clients/WsChannelCore.cs b/NewLife.Remoting/Clients/WsChannelCore.cs index 001c2cb..46811e5 100644 --- a/NewLife.Remoting/Clients/WsChannelCore.cs +++ b/NewLife.Remoting/Clients/WsChannelCore.cs @@ -1,4 +1,5 @@ #if NETCOREAPP +using System.Net.Sockets; using System.Net.WebSockets; using NewLife; using NewLife.Collections; @@ -141,6 +142,19 @@ private async Task DoPull(WebSocket socket, CancellationTokenSource source) catch (ThreadInterruptedException) { break; } catch (TaskCanceledException) { } catch (OperationCanceledException) { } + catch (ObjectDisposedException) { break; } + catch (WebSocketException wex) when ( + wex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely || + socket.State == WebSocketState.Aborted) + { + _client.Log?.Debug("[{0}]WebSocket连接断开[{1}]", _client.Name, wex.WebSocketErrorCode); + break; + } + catch (SocketException sex) when (IsNormalDisconnect(sex.SocketErrorCode)) + { + _client.Log?.Debug("[{0}]WebSocket连接断开[{1}]", _client.Name, sex.SocketErrorCode); + break; + } catch (Exception ex) { if (source.IsCancellationRequested) break;