From 05a8076fa586f44c709592d03a7c665914ee5302 Mon Sep 17 00:00:00 2001 From: "Alecio Furanze (Ale)" Date: Tue, 10 Dec 2024 23:19:47 +0200 Subject: [PATCH] fix. websocket client: create multiples connection on faster (around milliseconds) make port conflict --- .../partials/Websocket/HTTP.WebSocketTo.cs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/http/partials/Websocket/HTTP.WebSocketTo.cs b/src/http/partials/Websocket/HTTP.WebSocketTo.cs index 13bc6f8..da84ab6 100644 --- a/src/http/partials/Websocket/HTTP.WebSocketTo.cs +++ b/src/http/partials/Websocket/HTTP.WebSocketTo.cs @@ -14,6 +14,11 @@ public partial class HTTP { internal class WebsocketTo : IHTTP.WebSocketTo { + /// + /// Prevents port collision during rapid WebSocket client initialization + /// + private static readonly object CONNECT_LOCKER = new object(); + private readonly bool _isServerSide; private readonly WebSocket _socket; public readonly Dictionary Headers = new Dictionary(); @@ -56,10 +61,26 @@ public Task Open(Uri host) return Task.Run(async () => { + Thread.Sleep(500); + try { - var ws = new ClientWebSocket(); + ClientWebSocket ws; + lock (CONNECT_LOCKER) + { + // Why is this lock necessary? + // When creating multiple WebSocket clients in quick succession, the operating system may reuse the same + // local port for different connections before fully releasing the previous ones. This happens because + // ephemeral port allocation is fast but not always synchronized optimally for high-concurrency scenarios. + // + // By using this global lock (via CONNECT_LOCKER) and introducing a small delay, we allow the OS enough + // time to properly assign unique local ports for each connection. This effectively prevents port reuse + // issues and connection instability under heavy load. + Thread.Sleep(TimeSpan.FromMilliseconds(byte.MaxValue)); // (Only client side) + ws = new ClientWebSocket(); + } + foreach (var header in Headers) ws.Options.SetRequestHeader(header.Key, header.Value); _socket._on.OnModify?.Invoke(null, ws);