diff --git a/src/BootstrapBlazor/Extensions/ITcpSocketFactoryExtensions.cs b/src/BootstrapBlazor/Extensions/ITcpSocketFactoryExtensions.cs new file mode 100644 index 00000000000..0c639db77f9 --- /dev/null +++ b/src/BootstrapBlazor/Extensions/ITcpSocketFactoryExtensions.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using System.Runtime.Versioning; + +namespace BootstrapBlazor.Components; + +/// +/// 扩展方法类 +/// +[UnsupportedOSPlatform("browser")] +public static class ITcpSocketFactoryExtensions +{ + /// + /// Retrieves an existing TCP socket client by name or creates a new one using the specified IP address and port. + /// + /// The instance used to manage TCP socket clients. + /// The unique name identifying the TCP socket client. Cannot be null or empty. + /// The IP address of the endpoint to connect to. Must be a valid IPv4 or IPv6 address. + /// The port number of the endpoint to connect to. Must be within the range 0 to 65535. + /// An instance representing the TCP socket client associated with the specified + /// name. If no client exists with the given name, a new client is created and returned. + public static ITcpSocketClient GetOrCreate(this ITcpSocketFactory factory, string name, string ipAddress, int port) + { + var endPoint = Utility.ConvertToIpEndPoint(ipAddress, port); + return factory.GetOrCreate(name, endPoint); + } +} diff --git a/src/BootstrapBlazor/Services/TcpSocket/DefaultTcpSocketFactory.cs b/src/BootstrapBlazor/Services/TcpSocket/DefaultTcpSocketFactory.cs index d6573cd02fa..3ce84679043 100644 --- a/src/BootstrapBlazor/Services/TcpSocket/DefaultTcpSocketFactory.cs +++ b/src/BootstrapBlazor/Services/TcpSocket/DefaultTcpSocketFactory.cs @@ -16,11 +16,10 @@ class DefaultTcpSocketFactory(IServiceProvider provider) : ITcpSocketFactory { private readonly ConcurrentDictionary _pool = new(); - public ITcpSocketClient GetOrCreate(string host, int port = 0) + public ITcpSocketClient GetOrCreate(string name, IPEndPoint endPoint) { - return _pool.GetOrAdd($"{host}:{port}", key => + return _pool.GetOrAdd(name, key => { - var endPoint = Utility.ConvertToIpEndPoint(host, port); var client = new DefaultTcpSocketClient(endPoint) { Logger = provider.GetService>() @@ -29,10 +28,10 @@ public ITcpSocketClient GetOrCreate(string host, int port = 0) }); } - public ITcpSocketClient? Remove(string host, int port) + public ITcpSocketClient? Remove(string name) { ITcpSocketClient? client = null; - if (_pool.TryRemove($"{host}:{port}", out var c)) + if (_pool.TryRemove(name, out var c)) { client = c; } diff --git a/src/BootstrapBlazor/Services/TcpSocket/ITcpSocketFactory.cs b/src/BootstrapBlazor/Services/TcpSocket/ITcpSocketFactory.cs index b72069e2f43..f479250a5d1 100644 --- a/src/BootstrapBlazor/Services/TcpSocket/ITcpSocketFactory.cs +++ b/src/BootstrapBlazor/Services/TcpSocket/ITcpSocketFactory.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using System.Net; + namespace BootstrapBlazor.Components; /// @@ -11,21 +13,21 @@ namespace BootstrapBlazor.Components; public interface ITcpSocketFactory : IDisposable { /// - /// Retrieves an existing TCP socket associated with the specified host and port, or creates a new one if none - /// exists. + /// Retrieves an existing TCP socket client by name or creates a new one if it does not exist. /// - /// The hostname or IP address of the remote endpoint. Cannot be null or empty. - /// The port number of the remote endpoint. Must be a valid port number between 0 and 65535. - /// An instance representing the TCP socket for the specified host and port. - ITcpSocketClient GetOrCreate(string host, int port); + /// The unique name used to identify the TCP socket client. Cannot be null or empty. + /// The network endpoint to associate with the TCP socket client. Must be a valid instance. + /// An instance of representing the TCP socket client associated with the specified + /// name and endpoint. If a client with the given name already exists, the existing instance is returned; otherwise, + /// a new client is created. + ITcpSocketClient GetOrCreate(string name, IPEndPoint endPoint); /// - /// Removes the specified host and port combination from the collection. + /// Removes the TCP socket client associated with the specified name. /// - /// If the specified host and port combination does not exist in the collection, the method has - /// no effect. - /// The hostname to remove. Cannot be null or empty. - /// The port number associated with the host to remove. Must be a valid port number (0-65535). - /// An instance representing the TCP socket for the specified host and port. - ITcpSocketClient? Remove(string host, int port); + /// The name of the TCP socket client to remove. Cannot be or empty. + /// The removed instance if a client with the specified name exists; otherwise, . + ITcpSocketClient? Remove(string name); } diff --git a/test/UnitTest/Services/TcpSocketFactoryTest.cs b/test/UnitTest/Services/TcpSocketFactoryTest.cs index 67af9e4a901..dc5ca89ecbc 100644 --- a/test/UnitTest/Services/TcpSocketFactoryTest.cs +++ b/test/UnitTest/Services/TcpSocketFactoryTest.cs @@ -22,22 +22,21 @@ public void GetOrCreate_Ok() builder.AddProvider(new MockLoggerProvider()); }); sc.AddBootstrapBlazorTcpSocketFactory(); - var provider = sc.BuildServiceProvider(); var factory = provider.GetRequiredService(); - var client1 = factory.GetOrCreate("localhost", 0); + var client1 = factory.GetOrCreate("demo", "localhost", 0); client1.Close(); - var client2 = factory.GetOrCreate("localhost", 0); + var client2 = factory.GetOrCreate("demo", "localhost", 0); Assert.Equal(client1, client2); var ip = Dns.GetHostAddresses(Dns.GetHostName(), AddressFamily.InterNetwork).FirstOrDefault() ?? IPAddress.Loopback; - var client3 = factory.GetOrCreate(ip.ToString(), 0); + var client3 = factory.GetOrCreate("demo1", ip.ToString(), 0); // 测试不合格 IP 地址 - var client4 = factory.GetOrCreate("256.0.0.1", 0); + var client4 = factory.GetOrCreate("demo2", "256.0.0.1", 0); - var client5 = factory.Remove("256.0.0.1", 0); + var client5 = factory.Remove("demo2"); Assert.Equal(client4, client5); Assert.NotNull(client5); @@ -451,7 +450,7 @@ private static ITcpSocketClient CreateClient() sc.AddBootstrapBlazorTcpSocketFactory(); var provider = sc.BuildServiceProvider(); var factory = provider.GetRequiredService(); - var client = factory.GetOrCreate("localhost", 0); + var client = factory.GetOrCreate("test", "localhost", 0); return client; } diff --git a/test/UnitTest/Utils/UtilityTest.cs b/test/UnitTest/Utils/UtilityTest.cs index 839590248e5..b90980f7d0c 100644 --- a/test/UnitTest/Utils/UtilityTest.cs +++ b/test/UnitTest/Utils/UtilityTest.cs @@ -758,6 +758,10 @@ public void ConvertToIpEndPoint_Ok() { var ex = Assert.Throws(() => Utility.ConvertToIpEndPoint("localhost", 88990)); Assert.NotNull(ex); + + ex = null; + ex = Assert.Throws(() => Utility.ConvertToIpEndPoint("localhost", -1000)); + Assert.NotNull(ex); } [AutoGenerateClass(Align = Alignment.Center)]