P2: Flexible四类通信锁从全局静态改为按端口/IP粒度(ConcurrentDictionary),不同物理端口互不阻塞

This commit is contained in:
2026-09-14 13:53:46 +08:00
parent 8d8df56544
commit 7043a66a28
4 changed files with 62 additions and 42 deletions
+15 -10
View File
@@ -1,4 +1,5 @@
using Common.Attributes;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Text;
@@ -7,14 +8,18 @@ namespace DeviceCommand.Flexible
/// <summary>
/// 灵活型 TCP 通信类(免实例化,每次调用临时建立 TCP 连接)。
/// 支持字节/文本发送、定长字节读取、按结束符读取文本行四种操作,
/// 内部使用通信锁保证同一时刻只有一个 TCP 事务在执行,
/// 适用于偶发性、无需保持长连接的 TCP 设备通信场景。
/// 内部使用按端点粒度的通信锁保证同一端点同一时刻只有一个 TCP 事务在执行,
/// 不同端点之间互不阻塞,适用于偶发性、无需保持长连接的 TCP 设备通信场景。
/// </summary>
[ADPCommand]
public static class FTCP
{
// 通信锁:保证同一时刻只有一个 TCP 事务在执行
private static readonly SemaphoreSlim _commLock = new(1, 1);
// 按端点粒度的通信锁:同一端点同一时刻只有一个事务在执行,不同端点互不阻塞
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _commLocks = new();
/// <summary>获取指定端点的通信锁(不存在则自动创建)</summary>
private static SemaphoreSlim GetLock(string ipAddress, int port)
=> _commLocks.GetOrAdd($"{ipAddress}:{port}", _ => new SemaphoreSlim(1, 1));
#region Send
@@ -28,7 +33,7 @@ namespace DeviceCommand.Flexible
/// <param name="ct">异步取消令牌</param>
public static async Task (string ipAddress,int port,int sendTimeout, byte[] buffer, CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(ipAddress, port).WaitAsync(ct);
try
{
using var client = new TcpClient();
@@ -41,7 +46,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(ipAddress, port).Release();
}
}
@@ -73,7 +78,7 @@ namespace DeviceCommand.Flexible
/// <returns>实际读取到的字节数组(对端提前关闭时可能短于请求长度)</returns>
public static async Task<byte[]> (string ipAddress,int port,int receiveTimeout,int length,CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(ipAddress, port).WaitAsync(ct);
try
{
using var client = new TcpClient();
@@ -100,7 +105,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(ipAddress, port).Release();
}
}
@@ -115,7 +120,7 @@ namespace DeviceCommand.Flexible
/// <returns>去除结束符并去除首尾空白后的文本行</returns>
public static async Task<string> ( string ipAddress, int port, int receiveTimeout, string delimiter = "\n",CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(ipAddress, port).WaitAsync(ct);
try
{
using var client = new TcpClient();
@@ -147,7 +152,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(ipAddress, port).Release();
}
}