| | |
| | | { |
| | | public partial class TcpSocketServer |
| | | { |
| | | /// <summary> |
| | | /// 获取所有已连接客户端 ID 列表 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 返回当前在服务器注册的客户端标识列表。 |
| | | /// 这是一个只读列表的快照,线程安全。 |
| | | /// </remarks> |
| | | /// <returns>客户端 ID 列表</returns> |
| | | public IReadOnlyList<string> GetClientIds() |
| | | { |
| | | lock (_syncRoot) |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据设备 ID 获取客户端 ID |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 在设备绑定表中查找对应的客户端 ID。 |
| | | /// </remarks> |
| | | /// <param name="deviceId">设备唯一标识</param> |
| | | /// <returns>客户端 ID,如果未找到则返回 null</returns> |
| | | public string? GetClientIdByDevice(string deviceId) |
| | | { |
| | | lock (_syncRoot) |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 异步向指定设备发送消息 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 通过设备 ID 查找对应的客户端连接,然后发送消息。 |
| | | /// 如果设备未注册或连接不存在,返回 false。 |
| | | /// </remarks> |
| | | /// <param name="deviceId">目标设备唯一标识</param> |
| | | /// <param name="message">要发送的消息</param> |
| | | /// <returns>发送是否成功</returns> |
| | | public Task<bool> SendToDeviceAsync(string deviceId, string message) |
| | | { |
| | | var clientId = GetClientIdByDevice(deviceId); |
| | |
| | | return SendToClientAsync(clientId, message); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 异步向指定客户端发送消息 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 使用帧格式发送消息(添加头尾标识)。 |
| | | /// 每个客户端的发送操作是互斥的(通过信号量实现)。 |
| | | /// 如果客户端未连接或不存在,发送失败返回 false。 |
| | | /// </remarks> |
| | | /// <param name="clientId">目标客户端 ID</param> |
| | | /// <param name="message">要发送的消息</param> |
| | | /// <returns>发送是否成功</returns> |
| | | public async Task<bool> SendToClientAsync(string clientId, string message) |
| | | { |
| | | TcpClient? client; |
| | |
| | | |
| | | enc ??= _textEncoding; |
| | | |
| | | // 获取客户端发送锁 |
| | | if (sem != null) await sem.WaitAsync(); |
| | | try |
| | | { |
| | | // 发送消息 |
| | | var ns = client.GetStream(); |
| | | var data = enc.GetBytes((message ?? string.Empty) + "\n"); |
| | | var framedMessage = BuildFramedMessage(message); |
| | | var data = enc.GetBytes(framedMessage); |
| | | await ns.WriteAsync(data, 0, data.Length); |
| | | } |
| | | finally |
| | |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 异步广播消息到所有客户端 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 将消息发送给所有已连接的客户端。 |
| | | /// 如果某个客户端发送失败,不影响其他客户端的发送。 |
| | | /// </remarks> |
| | | /// <param name="message">要广播的消息</param> |
| | | public async Task BroadcastAsync(string message) |
| | | { |
| | | List<TcpClient> clients; |
| | |
| | | clients = _clients.Values.ToList(); |
| | | } |
| | | |
| | | // 并行发送消息到所有客户端 |
| | | await Task.WhenAll(clients.Select(c => Task.Run(async () => |
| | | { |
| | | try { await SendAsync(c, message); } catch { } |
| | | try { await SendMessageAsync(c, message); } catch { } |
| | | }))); |
| | | } |
| | | |
| | | public static async Task SendAsync(TcpClient client, string message) |
| | | /// <summary> |
| | | /// 通过 NetworkStream 发送消息 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 直接使用 TcpClient 的 NetworkStream 发送消息。 |
| | | /// 消息会添加帧头帧尾。 |
| | | /// </remarks> |
| | | /// <param name="client">TCP 客户端</param> |
| | | /// <param name="message">消息内容</param> |
| | | public async Task SendMessageAsync(TcpClient client, string message) |
| | | { |
| | | if (client == null || !client.Connected) |
| | | { |
| | |
| | | } |
| | | |
| | | NetworkStream stream = client.GetStream(); |
| | | var data = Encoding.UTF8.GetBytes((message ?? string.Empty) + "\n"); |
| | | var framedMessage = BuildFramedMessage(message); |
| | | var data = _textEncoding.GetBytes(framedMessage); |
| | | await stream.WriteAsync(data, 0, data.Length); |
| | | } |
| | | } |