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
}