using System.Net; using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; using SocketTool.Entity; namespace SocketTool; /// /// socket 客户端 .net6 版 /// public class SocketClient { #region 全局变量 private List NeedConnectSockets = []; // 需要连接的socket int IPCount;//传入的连接数 #endregion #region 全局属性 /// /// 字符串解析格式 /// private Encoding? Encod { get; set; } #endregion /// /// socket连接类,自带自动重连功能 /// 传入参数示例:127.0.0.1:8090 /// /// /// /// public SocketClient(Encoding? encoding, params string?[] IPPorts) { Encod = encoding; IPCount = IPPorts.Length;//数量赋值 foreach (string? IPPort in IPPorts) { if (string.IsNullOrEmpty(IPPort)) { continue; } string ipAndPort = IPPort.Replace(":", ":");//将中文冒号替换成英文冒号 if (!ipAndPort.Contains(':')) { // 不含有端口号的直接抛异常,必须处理 throw new Exception($"地址:{IPPort} 格式不正确,必须处理以后才能正常运行。"); } string[] ipp = ipAndPort.Split(':'); if (ipp.Length != 2 || string.IsNullOrEmpty(ipp[0]) || string.IsNullOrEmpty(ipp[1])) { // 拆分后没有地址或者端口号的直接抛异常,必须处理 throw new Exception($"地址:{IPPort} 格式不正确,必须处理以后才能正常运行。"); } string IP = ipp[0]; int Port = CheckIP(IP, ipp[1]); if (Port != 0) { Socket socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); NeedConnectSockets.Add(new SocketModel() { Socket = socket, SocketIp = IPPort, IsConnected = false, HostEP = new IPEndPoint(IPAddress.Parse(IP), Port) }); } } } /// /// 检查IP地址和端口号是否满足格式 /// 如果格式错误返回0,否则返回Int格式的端口号 /// /// /// /// private static int CheckIP(string? IP, string? Portstr) { if (string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(Portstr)) { throw new Exception("传入的IP或者端口存在异常"); } int Port;//int格式的端口号 try { Port = Convert.ToInt32(Portstr); } catch { return 0; } string CheckString = "^((1[0-9][0-9]\\.)|(2[0-4][0-9]\\.)|(25[0-5]\\.)|([1-9][0-9]\\.)|([0-9]\\.)){3}((1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])|([1-9][0-9])|([0-9]))$"; bool IsIPOK = Regex.IsMatch(IP, CheckString); if (!IsIPOK || Port < 1 || Port > 65535) { throw new Exception($"地址:{IP} 的端口号:{Portstr} 格式不正确,必须处理以后才能正常运行。"); } return Port; } /// /// 连接事件,需要调用 /// public void Connect() { if (NeedConnectSockets.Count < 1) { return; } // 连接 socket foreach (SocketModel needConnectSocket in NeedConnectSockets) { Thread connectSocket = new(() => { ConnectSocket(needConnectSocket); }) { IsBackground = true }; connectSocket.Start(); //Task.Factory.StartNew(()=>ConnectSocket(needConnectSocket)); } // 启用重连 Thread reConnectSocket = new(ReConnectSocket) { IsBackground = true }; reConnectSocket.Start(); //Task.Factory.StartNew(ReConnectSocket); } /// /// 连接 socket /// /// private void ConnectSocket(SocketModel socketInfo) { while (true)//此循环经本人考虑再三后加上,去掉此循环将导致=>在服务端未开启的情况下开启客户端,后面服务端开启,虽然可以通过下方重连连上服务端,但无法接受数据 { try { SocketConnecting?.Invoke(socketInfo.SocketIp ?? "");//触发连接中事件 socketInfo.Socket!.Connect(socketInfo.HostEP!);//尝试连接 SocketOnline?.Invoke(socketInfo.SocketIp ?? "");//触发连接成功事件 socketInfo.Thread = Thread.CurrentThread; socketInfo.IsConnected = true; break; } catch (Exception ex) { SocketConnectFail?.Invoke(socketInfo.SocketIp ?? "", ex);//出发连接中事件 Thread.Sleep(2000); } } Socket socket = socketInfo.Socket; // 拉取地址 while (true) { byte[] recvBytes = new byte[1024 * 1024]; try { int bytes = socket.Receive(recvBytes, recvBytes.Length, SocketFlags.None); if (bytes <= 0) continue; GetTcpData?.BeginInvoke(recvBytes, socketInfo.SocketIp ?? "", null, null); if (GetTcpData != null) continue; string? recvStr = Encod?.GetString(recvBytes, 0, bytes); //此处编码方式请根据服务端发送的编码方式修改对应,否则可能造成部分字符乱码 if (string.IsNullOrEmpty(recvStr)) continue; if (recvStr.Trim().Length > 0) { GetSocketMessage?.Invoke(recvStr, socketInfo.SocketIp ?? ""); if (HandleCodeInfo != null) { ManCode(recvStr, socketInfo.SocketIp ?? ""); //处理条码并触发其他事件 } } } catch (Exception ex) { _ = ex; RecevErrEvent?.Invoke(socketInfo.SocketIp ?? "", ex); socketInfo.IsConnected = false; return; } } } /// /// 重新连接 Socket /// private void ReConnectSocket() { Thread.Sleep(5000); while (true) { foreach (SocketModel needConnectSocket in NeedConnectSockets) { Socket socket = needConnectSocket.Socket!; Thread.Sleep(300); try { try { socket.SendTimeout = 1000; socket.Send(Encoding.ASCII.GetBytes(" ")); if (!socket.Connected) { needConnectSocket.IsConnected = false; } } catch (Exception ex) { _ = ex.ToString(); SocketOffline?.Invoke(needConnectSocket.SocketIp ?? ""); //触发掉线事件 try { socket.Close(); //关闭已经断开的socket } catch (Exception exception) { _ = exception; } Thread connectSocket = new(() => { ConnectSocket(needConnectSocket); }) { IsBackground = true }; connectSocket.Start(); //Task.Factory.StartNew(() => ConnectSocket(needConnectSocket)); } } catch (Exception ex) { _ = ex.ToString(); } } } } /// /// 处理收到的条码,并引发事件 /// /// /// private void ManCode(string? code, string? IPAddress) { //多线程处理,增加程序运行速度 ThreadPool.QueueUserWorkItem((useless) => { List? scanCodeClasses = SplitCode(code, IPAddress); if (scanCodeClasses != default) { foreach (ScanCodeClass scc in scanCodeClasses) { HandleCodeInfo?.Invoke(scc); } } }); } /// /// 拆条码,将前缀和条码拆下来 /// /// /// /// private List? SplitCode(string? GetCode, string? Ipaddress) { if (string.IsNullOrEmpty(GetCode) || string.IsNullOrEmpty(Ipaddress)) { return default; } if (!GetCode.Contains('(')) { return default; } List sccs = []; string[] GetCodeCuts = GetCode.Split('('); foreach (string GetCodeCut in GetCodeCuts) { if (GetCodeCut == "" || GetCodeCut.Trim().Length == 0 || !GetCodeCut.Contains(')')) { continue; } string[] ScanCode = GetCodeCut.Split(')'); if (ScanCode.Length < 2) { continue; } ScanCodeClass scc = new() { IpAddress = Ipaddress, ScanID = Convert.ToInt32(ScanCode[0]), StrScanID = ScanCode[0], Code = ScanCode[1] }; sccs.Add(scc); } return sccs; } #region 事件 public delegate void HandleInfo(ScanCodeClass scc); /// /// 条码处理事件, /// ScanID或者ScanIDStr为null的是没有前缀的条码 /// public event HandleInfo? HandleCodeInfo; public delegate void GetMessage(string Message, string IPAddress); /// /// 条码处理事件, /// public event GetMessage? GetSocketMessage; public delegate void GetData(byte[] data, string IPAddress); /// /// 字节返回事件 /// public event GetData? GetTcpData; public delegate void OffLine(string IPAddress); /// /// 当有地址掉线时触发 /// public event OffLine? SocketOffline; public delegate void OnLine(string IPAddress); /// /// 当地址连接成功时触发 /// public event OnLine? SocketOnline; public delegate void Connecting(string IPAddress); /// /// 当地址连接正在连接时触发 /// public event Connecting? SocketConnecting; public delegate void ConnectFail(string IPAddress, Exception ex); /// /// 当地址连接正在连接时触发 /// public event ConnectFail? SocketConnectFail; public delegate void RecevErr(string IPAddress, Exception ex); /// /// 当地址连接接收数据异常时触发 /// public event RecevErr? RecevErrEvent; #endregion }