当前位置: 首页 > ai >正文

c#:TCP服务端管理类

TCP客户端连接多个服务端的类

1.架构图

在这里插入图片描述

2.创建TCP 客户端与服务端通信的工具类

注:TcpClientAsyncTool类中是客户端连接服务端的,TcpClient 实质是Server,套用服务端连接客户端的,使用过程中自行修改名称,本案例暂未修改。连接使用异步操作,其余为同步执行的。

    public class TcpClientAsyncTool{private TcpClient _tcpClient;public bool isConnected = false;public IPAddress IPAddress { get; private set; }private int _port;// 端口号private int _connectTimeout;// 连接超时时间(毫秒)private byte[] _receiveBuffer = new byte[1024];// 接收服务端数据/// <summary>/// 服务端连接信/// </summary>/// <param name="ip">ip地址</param>/// <param name="port">端口号</param>/// <param name="connectTimeout">连接超时时间</param>public TcpClientAsyncTool(string ip, int port, int connectTimeout = 2000){_tcpClient = new TcpClient();this.IPAddress = IPAddress.Parse(ip);this._port = port;this._connectTimeout = connectTimeout;}/// <summary>/// 异步连接服务端/// </summary>/// <param name="connectDelegate"></param>/// <returns></returns>public async Task<(bool Success, string ErrorMsg)> ConnectAsync(Action connectDelegate = null){if (_tcpClient.Connected){isConnected = true;return (true, string.Empty);}try{var connectTask = Task.Factory.FromAsync(_tcpClient.BeginConnect(IPAddress, _port, null, null),_tcpClient.EndConnect);var timeoutTask = Task.Delay(_connectTimeout);var completedTask = await Task.WhenAny(connectTask, timeoutTask);if (completedTask == timeoutTask){try { _tcpClient.Close(); } catch { }return (false, "连接超时");}await connectTask;if (!_tcpClient.Connected){return (false, "连接失败");}connectDelegate?.Invoke();isConnected = true;return (true, string.Empty);}catch (Exception ex){isConnected = false;try { _tcpClient.Close(); } catch { }return (false, ex.Message);}}/// <summary>/// 断开连接/// </summary>/// <param name="errorMsg">错误信息</param>/// <returns>是否成功</returns>public bool DisConnect(out string errorMsg){errorMsg = string.Empty;if (!_tcpClient.Connected){isConnected = false;return true;}try{_tcpClient.Close();isConnected = false;return true;}catch (Exception ex){errorMsg = ex.Message;isConnected = false;return false;}}/// <summary>/// 同步发送数据/// </summary>/// <param name="sendBytes">要发送的字节数据</param>/// <param name="errorMsg">错误信息</param>/// <returns>是否发送成功</returns>public bool SendData(byte[] sendBytes, out string errorMsg){errorMsg = string.Empty;if (!isConnected || !_tcpClient.Connected){errorMsg = "客户端未连接";return false;}if (sendBytes == null || sendBytes.Length == 0){errorMsg = "发送数据不能为空";return false;}try{NetworkStream networkStream = _tcpClient.GetStream();if (!networkStream.CanWrite){errorMsg = "网络流不可写";return false;}IAsyncResult asyncResult = networkStream.BeginWrite(sendBytes, 0, sendBytes.Length, null, null);networkStream.EndWrite(asyncResult);return true;}catch (Exception ex){errorMsg = ex.Message;isConnected = false;try { _tcpClient.Close(); } catch { }return false;}}/// <summary>/// 接收数据/// </summary>/// <param name="result">是否接收成功</param>/// <param name="errorMsg">错误信息</param>/// <returns>接收到的字节数据,如果失败返回null</returns>public byte[] ReceiveData(out bool result, out string errorMsg){result = false;errorMsg = string.Empty;if (!isConnected || !_tcpClient.Connected){errorMsg = "客户端未连接";return null;}try{NetworkStream networkStream = _tcpClient.GetStream();if (!networkStream.CanRead){errorMsg = "网络流不可读";return null;}// 清空接收缓冲区Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);IAsyncResult asyncResult = networkStream.BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, null, null);int readBytes = networkStream.EndRead(asyncResult);if (readBytes <= 0){isConnected = false;errorMsg = "连接已关闭";return null;}byte[] readByteArray = new byte[readBytes];Array.Copy(_receiveBuffer, readByteArray, readBytes);result = true;return readByteArray;}catch (Exception ex){errorMsg = ex.Message;isConnected = false;try { _tcpClient.Close(); } catch { }return null;}}}

3.创建类用于管理多个连接的服务端Server

    public class TcpClientManager : IDisposable{private readonly List<(string Ip, int Port)> _clientConfigurations;// 存储服务端配置的IP和端口private readonly ConcurrentDictionary<(string Ip, int Port), TcpClientAsyncTool> _clients =new ConcurrentDictionary<(string Ip, int Port), TcpClientAsyncTool>();//为服务端创建一个字典,存储IP和端口对应的TcpClientAsyncTool对象public event Action<string, byte[]> OnMessageReceivedWithIpPort;// 接收数据事件,包含IP和接收服务端返回的数据信息public event Action<string, bool> OnConnectionStateChanged; //设备连接状态变化事件private bool _disposed = false;// 确保Dispose方法只被调用一次public TcpClientManager(List<(string Ip, int Port)> clientConfigurations){_clientConfigurations = clientConfigurations ?? throw new ArgumentNullException(nameof(clientConfigurations));}/// <summary>/// 初始化服务端连接/// </summary>/// <returns></returns>public async Task InitializeAsync(){var tasks = new List<Task>();foreach (var (ip, port) in _clientConfigurations){tasks.Add(Task.Run(async () =>{var client = new TcpClientAsyncTool(ip, port);if (_clients.TryAdd((ip, port), client)){await ConnectToServer(ip, port);_ = StartReceivingMessages(ip, port);}}));}await Task.WhenAll(tasks);}public void SendCommandToServer(string ip, int port, byte[] byteData){if (string.IsNullOrEmpty(ip))throw new ArgumentException("IP address cannot be null or empty.", nameof(ip));if (port <= 0 || port > 65535)throw new ArgumentException("Port number is invalid.", nameof(port));if (byteData == null)throw new ArgumentNullException(nameof(byteData));if (_clients.TryGetValue((ip, port), out var client)){string errorMsg = string.Empty;client.SendData(byteData, out errorMsg);if (!string.IsNullOrEmpty(errorMsg)){Console.WriteLine($"Error sending data to {ip}:{port}: {errorMsg}");}}else{OnConnectionStateChanged?.Invoke(ip, false); // 触发断开事件Console.WriteLine($"Client {ip}:{port} is not connected.");}}/// <summary>/// 判断客户端与服务端是否连接/// </summary>/// <param name="ip">IP</param>/// <returns>返回连接状态</returns>/// <exception cref="ArgumentException"></exception>public bool IsDeviceConnected(string ip){if (string.IsNullOrEmpty(ip))throw new ArgumentException("IP address cannot be null or empty.", nameof(ip));foreach (var client in _clients.Values){if ((client.IPAddress).ToString() == (ip) && client.isConnected) {return true;}}return false;}/// <summary>/// 服务端接收数据处理/// </summary>/// <param name="ip"></param>/// <param name="port"></param>/// <returns></returns>private async Task StartReceivingMessages(string ip, int port){try{while (_clients.TryGetValue((ip, port), out var client) && client.isConnected){try{bool result = false;string errorMsg = string.Empty;byte[] response = client.ReceiveData(out result, out errorMsg);if (response != null && result){OnMessageReceivedWithIpPort?.Invoke($"{ip}", response); //订阅接收数据事件,数据包含IP和端口}else if (!string.IsNullOrEmpty(errorMsg)){Console.WriteLine($"Receive error from {ip}:{port}: {errorMsg}");break; // 退出循环,尝试重新连接}}catch (Exception ex){Console.WriteLine($"Error receiving data from {ip}:{port}: {ex.Message}");break; // 退出循环,尝试重新连接}await Task.Delay(10);}}finally{await Task.Delay(1000);_ = ConnectToServer(ip, port);_ = StartReceivingMessages(ip, port); }}/// <summary>/// 异步连接服务端/// </summary>/// <param name="ip"></param>/// <param name="port"></param>/// <returns></returns>private async Task ConnectToServer(string ip, int port){if (_disposed) return;try{if (_clients.TryGetValue((ip, port), out var client)){if (!client.isConnected){await client.ConnectAsync();OnConnectionStateChanged?.Invoke(ip, client.isConnected); // 触发断开事件}}}catch (Exception ex){Console.WriteLine($"Error connecting to {ip}:{port}: {ex.Message}");}}/// <summary>/// 断开连接到服务端/// </summary>/// <param name="ip"></param>/// <param name="port"></param>public void DisconnectToServer(string ip, int port){if (_clients.TryRemove((ip, port), out var client)){string errorMsg = string.Empty;client.DisConnect(out errorMsg);OnConnectionStateChanged?.Invoke(ip, false); // 触发断开事件if (!string.IsNullOrEmpty(errorMsg)){Console.WriteLine($"Error disconnecting {ip}:{port}: {errorMsg}");}}}public void Dispose(){Dispose(true);GC.SuppressFinalize(this);}/// <summary>/// 关闭连接和释放资源/// </summary>/// <param name="disposing"></param>protected virtual void Dispose(bool disposing){if (!_disposed){if (disposing){// 释放托管资源foreach (var client in _clients.Values){try{string errorMsg = string.Empty;client.DisConnect(out errorMsg);if (!string.IsNullOrEmpty(errorMsg)){Console.WriteLine($"Error during disconnect: {errorMsg}");}}catch (Exception ex){Console.WriteLine($"Exception during client disposal: {ex.Message}");}}_clients.Clear();}_disposed = true;}}~TcpClientManager(){Dispose(false);}}
http://www.xdnf.cn/news/15843.html

相关文章:

  • Spark专栏开篇:它从何而来,为何而生,凭何而强?
  • EPLAN 电气制图(十): 继电器控制回路绘制(下)放料、放灰
  • 机器学习基础:从数据到智能的入门指南
  • 第三章自定义检视面板_创建自定义编辑器类_编辑器操作的撤销与恢复(本章进度3/9)
  • MySQL锁(一) 概述与分类
  • 算法讲解--复写零
  • 旋转位置编码-ROPE简单理解
  • 《剥开洋葱看中间件:Node.js请求处理效率与错误控制的深层逻辑》
  • go-redis Pipeline 与事务
  • 国产电钢琴性价比实战选购指南
  • Selenium 处理动态网页与等待机制详解
  • SpringBoot 整合 Langchain4j 实现会话记忆存储深度解析
  • 面试高频题 力扣 417. 太平洋大西洋水流问题 洪水灌溉(FloodFill) 深度优先遍历(dfs) 暴力搜索 C++解题思路 每日一题
  • 从零到一MCP快速入门实战【1】
  • MySQL锁(二) 共享锁与互斥锁
  • PHPStorm携手ThinkPHP8:开启高效开发之旅
  • 【华为机试】23. 合并 K 个升序链表
  • Leetcode 06 java
  • LeetCode 121. 买卖股票的最佳时机
  • 试用SAP BTP 02:试用SAP HANA Cloud
  • 算法分析--时间复杂度
  • Hadoop小文件合并技术深度解析:HAR文件归档、存储代价与索引结构
  • Function Callingの进化路:源起篇
  • gradle关于dependency-management的使用
  • 【实证分析】会计稳健性指标分析-ACF、CScore、Basu模型(2000-2023年)
  • 贝叶斯分类器的相关理论学习
  • Qwen3-8B 的 TTFT 性能分析:16K 与 32K 输入 Prompt 的推算公式与底层原理详解
  • 乐观锁实现原理笔记
  • 【论文阅读笔记】RF-Diffusion: Radio Signal Generation via Time-Frequency Diffusion
  • 考研最高效的准备工作是什么