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

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.dtcms.com/a/288644.html

相关文章:

  • 正点原子stm32F407学习笔记10——输入捕获实验
  • 2025 年科技革命时刻表:四大关键节点将如何重塑未来?
  • 内网后渗透攻击过程(实验环境)--3、横向攻击
  • SQL 调优第一步:EXPLAIN 关键字全解析
  • 【已解决】GitHub SSH 连接失败解决方案:Permission Denied (publickey) 错误修复指南
  • [Linux]进程 / PID
  • 30天打牢数模基础-决策树讲解
  • Linux入门篇学习——NFS 服务器的搭建和使用和开发板固件烧录
  • Spring Boot 第一天知识汇总
  • 【Java项目安全基石】登录认证实战:Session/Token/JWT用户校验机制深度解析
  • 相似度计算
  • 「Java案例」利用方法求反素数
  • Facebook 开源多季节性时间序列数据预测工具:Prophet 饱和预测 Saturating Forecasts
  • dynamic_cast的实现原理
  • Beamer-LaTeX学习(教程批注版)【6】
  • Elasticsearch 简化指南:GCP Google Compute Engine
  • GPT-4o mini TTS:领先的文本转语音技术
  • 随着GPT-5测试中泄露OpenAI 预计将很快发布 揭秘GPT-5冲击波:OpenAI如何颠覆AI战场,碾压谷歌和Claude?
  • prometheus 黑盒监控和docker检测
  • mysql第三次作业
  • 学习寄存器——GPIO(二)学习BSRR BRR ODR寄存器的原子性和在HAL库的应用
  • 【Go语言-Day 22】解耦与多态的基石:深入理解 Go 接口 (Interface) 的核心概念
  • 【详细笔记】两类曲线积分转换
  • 群组功能实现指南:从数据库设计到前后端交互,上班第二周
  • 【数据结构】揭秘二叉树与堆--用C语言实现堆
  • 人工智能之数学基础:随机实验、样本空间、随机事件
  • Docker Desktop 入门教程(Windows macOS)
  • 深度学习图像分类数据集—百种病虫害分类
  • Python绘图小工具开发:从零构建数据可视化利器
  • 股票及金融笔记