c#:TCP服务端管理类_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];// 接收服务端数据 /// /// 服务端连接信 /// /// ip地址 /// 端口号 /// 连接超时时间 public TcpClientAsyncTool(string ip, int port, int connectTimeout = 2000) { _tcpClient = new TcpClient(); this.IPAddress = IPAddress.Parse(ip); this._port = port; this._connectTimeout = connectTimeout; } /// /// 异步连接服务端 /// /// /// 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); } } /// /// 断开连接 /// /// 错误信息 /// 是否成功 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; } } /// /// 同步发送数据 /// /// 要发送的字节数据 /// 错误信息 /// 是否发送成功 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; } } /// /// 接收数据 /// /// 是否接收成功 /// 错误信息 /// 接收到的字节数据,如果失败返回null 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)); } /// /// 初始化服务端连接 /// /// 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.\"); } } /// /// 判断客户端与服务端是否连接 /// /// IP /// 返回连接状态 /// 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; } /// /// 服务端接收数据处理 /// /// /// /// 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); } } /// /// 异步连接服务端 /// /// /// /// 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}\"); } } /// /// 断开连接到服务端 /// /// /// 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); } /// /// 关闭连接和释放资源 /// /// 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); } }