wcs_server_kate_suzhou/Tools/SocketTool/SocketClient.cs

362 lines
12 KiB
C#
Raw Permalink Normal View History

2024-05-14 16:30:56 +08:00
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using SocketTool.Entity;
namespace SocketTool;
/// <summary>
/// socket 客户端 .net6 版
/// </summary>
public class SocketClient
{
#region
private List<SocketModel> NeedConnectSockets = []; // 需要连接的socket
int IPCount;//传入的连接数
#endregion
#region
/// <summary>
/// 字符串解析格式
/// </summary>
private Encoding? Encod { get; set; }
#endregion
/// <summary>
/// socket连接类自带自动重连功能
/// 传入参数示例127.0.0.1:8090
/// </summary>
/// <param name="encoding"></param>
/// <param name="IPPorts"></param>
/// <exception cref="Exception"></exception>
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)
});
}
}
}
/// <summary>
/// 检查IP地址和端口号是否满足格式
/// 如果格式错误返回0否则返回Int格式的端口号
/// </summary>
/// <param name="IP"></param>
/// <param name="Portstr"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 连接事件,需要调用
/// </summary>
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);
}
/// <summary>
/// 连接 socket
/// </summary>
/// <param name="socketInfo"></param>
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;
2024-05-14 16:30:56 +08:00
string? recvStr = Encod?.GetString(recvBytes, 0, bytes); //此处编码方式请根据服务端发送的编码方式修改对应,否则可能造成部分字符乱码
if (string.IsNullOrEmpty(recvStr)) continue;
2024-05-14 16:30:56 +08:00
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;
}
}
}
/// <summary>
/// 重新连接 Socket
/// </summary>
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();
}
}
}
}
/// <summary>
/// 处理收到的条码,并引发事件
/// </summary>
/// <param name="code"></param>
/// <param name="IPAddress"></param>
private void ManCode(string? code, string? IPAddress)
{
//多线程处理,增加程序运行速度
ThreadPool.QueueUserWorkItem((useless) =>
{
List<ScanCodeClass>? scanCodeClasses = SplitCode(code, IPAddress);
if (scanCodeClasses != default)
{
foreach (ScanCodeClass scc in scanCodeClasses)
{
HandleCodeInfo?.Invoke(scc);
}
}
});
}
/// <summary>
/// 拆条码,将前缀和条码拆下来
/// </summary>
/// <param name="GetCode"></param>
/// <param name="Ipaddress"></param>
/// <returns></returns>
private List<ScanCodeClass>? SplitCode(string? GetCode, string? Ipaddress)
{
if (string.IsNullOrEmpty(GetCode) || string.IsNullOrEmpty(Ipaddress))
{
return default;
}
if (!GetCode.Contains('('))
{
return default;
}
List<ScanCodeClass> 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);
/// <summary>
/// 条码处理事件,
/// ScanID或者ScanIDStr为null的是没有前缀的条码
/// </summary>
public event HandleInfo? HandleCodeInfo;
public delegate void GetMessage(string Message, string IPAddress);
/// <summary>
/// 条码处理事件,
/// </summary>
public event GetMessage? GetSocketMessage;
public delegate void GetData(byte[] data, string IPAddress);
/// <summary>
/// 字节返回事件
/// </summary>
public event GetData? GetTcpData;
2024-05-14 16:30:56 +08:00
public delegate void OffLine(string IPAddress);
/// <summary>
/// 当有地址掉线时触发
/// </summary>
public event OffLine? SocketOffline;
public delegate void OnLine(string IPAddress);
/// <summary>
/// 当地址连接成功时触发
/// </summary>
public event OnLine? SocketOnline;
public delegate void Connecting(string IPAddress);
/// <summary>
/// 当地址连接正在连接时触发
/// </summary>
public event Connecting? SocketConnecting;
public delegate void ConnectFail(string IPAddress, Exception ex);
/// <summary>
/// 当地址连接正在连接时触发
/// </summary>
public event ConnectFail? SocketConnectFail;
public delegate void RecevErr(string IPAddress, Exception ex);
/// <summary>
/// 当地址连接接收数据异常时触发
/// </summary>
public event RecevErr? RecevErrEvent;
#endregion
}