P2: Flexible四类通信锁从全局静态改为按端口/IP粒度(ConcurrentDictionary),不同物理端口互不阻塞
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user