wcs_server_kate_suzhou/Tools/SocketTool/SocketClient.cs

361 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
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;
}
}
}
/// <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 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
}