using NX_CommonClassLibrary; using NX_LogClassLibrary; using NX_ModelClassLibrary.BaseModel; using NX_ModelClassLibrary.CustomEnum; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace NX_SocketUtility { /// /// 先导智能Socket服务端操作帮助类 /// Copyright20181102 (C) sunyalong /// 允许修改、添加满足自己项目的需要。 /// 添加、修改后请详细注释。违者会强制删除不予采用。 /// public class LeadSocketServerHelper { #region 事件 public event GetMessageEventHandler MessageEvent; /// /// 触发接收到Socket客户端消息的委托事件 /// /// 数据buffer /// ip /// 数据长度 /// 事件类对象 protected virtual void OnNewMessage(object sender, string ip, int dataLength, EventArgs e) { MessageEvent?.Invoke(sender, ip, dataLength, e); } public event GetAcceptEventHandler AcceptEvent; /// /// 触发Socket客户接入服务端的委托事件 /// /// 链接进入的IP(Socket对象) /// 事件类对象 protected virtual void OnAcceptEvent(object sender, EventArgs e) { AcceptEvent?.Invoke(sender, e); } public event GetCloseEventHandler CloseEvent; /// /// 触发关闭链接委托事件 /// /// 链接进入的IP(Socket对象) /// 事件类对象 protected virtual void OnCloseEvent(object sender, EventArgs e) { CloseEvent?.Invoke(sender, e); } #endregion #region 全局变量 /// /// Socket服务端套接字对象 /// public Socket SocketServerListen; /// /// Socket客户端套接字对象字典 /// public ConcurrentDictionary dicSockClientList = new ConcurrentDictionary(); /// /// Socket客户端接受数据线程字典 /// public ConcurrentDictionary dicSockThreadList = new ConcurrentDictionary(); /// /// 监听客户端连接的线程标识 /// private bool Flag_Listen = false; #endregion #region 方法 /// /// 开启监听 /// /// 服务端IP地址 /// 端口号 public void StartListen(string ip, int port) { try { //当开始监听的时候,在服务器端创建一个负责监听IP地址跟端口号的Socket SocketServerListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //获取ip地址 IPAddress ipadd = IPAddress.Parse(ip); //创建一个网络通信节点,这个通信节点包含了ip地址,端口号。 //这里的端口我们设置为1029,这里设置大于1024,为什么自己查一下端口号范围使用说明。 IPEndPoint endpoint = new IPEndPoint(ipadd, Convert.ToInt32(port));//创建一个网络通信节点,该节点中包含了IP地址和端口号. //Socket绑定网络通信节点 SocketServerListen.Bind(endpoint); //设置监听队列 SocketServerListen.Listen(100); LogHelper.WriteLog($"Socket服务端 ip地址:【{ip}】端口号:【{port}】 开启监听成功!", LogTypeEnum.SocketRun); Flag_Listen = true; } catch (Exception ex) { LogHelper.WriteLog($"Socket服务端 ip地址:【{ip}】端口号:【{port}】 开启监听发生异常:【{ex.Message}】", LogTypeEnum.SocketErr); } } #region UDP协议 public void StartListenUdp(string ip, int port, List allBarcodeScannerList) { try { //当开始监听的时候,在服务器端创建一个负责监听IP地址跟端口号的Socket SocketServerListen = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //获取ip地址 IPAddress ipadd = IPAddress.Parse(ip); //创建一个网络通信节点,这个通信节点包含了ip地址,端口号。 //这里的端口我们设置为1029,这里设置大于1024,为什么自己查一下端口号范围使用说明。 IPEndPoint endpoint = new IPEndPoint(ipadd, Convert.ToInt32(port));//创建一个网络通信节点,该节点中包含了IP地址和端口号. //Socket绑定网络通信节点 SocketServerListen.Bind(endpoint); LogHelper.WriteLog($"Socket服务端 ip地址:【{ip}】端口号:【{port}】 开启监听成功!", LogTypeEnum.SocketRun); ParameterizedThreadStart par = new ParameterizedThreadStart(ReciveMsg); Thread t = new Thread(par) { IsBackground = true }; t.Start(allBarcodeScannerList); } catch (Exception ex) { LogHelper.WriteLog($"Socket服务端 ip地址:【{ip}】端口号:【{port}】 开启监听发生异常:【{ex.Message}】", LogTypeEnum.SocketErr); } } void ReciveMsg(object allBarcodeScannerList) { List scannerList = allBarcodeScannerList as List; while (true) { try { EndPoint point = new IPEndPoint(IPAddress.Any, 0); byte[] buffer = new byte[1024 * 1024]; int length = SocketServerListen.ReceiveFrom(buffer, ref point); if (scannerList.FindAll(x => x.IpAddress == ((IPEndPoint)point).Address.ToString()).Count > 0) { //string message = Encoding.UTF8.GetString(buffer, 0, length); //触发接收到Socket客户端发送数据的事件 OnNewMessage(buffer, point.ToString(), length, EventArgs.Empty); } } catch { } } } #endregion /// /// 循环监听客户端的连接 /// public void ListeneSocketClientConnectAccept() { while (Flag_Listen) { try { Socket newSoket = SocketServerListen.Accept(); string ipAddress = newSoket.RemoteEndPoint.ToString(); ParameterizedThreadStart par = new ParameterizedThreadStart(RecevieMsg); Thread thread = new Thread(par) { IsBackground = true }; thread.Start(newSoket); dicSockClientList.TryAdd(ipAddress, newSoket); dicSockThreadList.TryAdd(ipAddress,thread); //触发Socket客户接入服务端事件 OnAcceptEvent(ipAddress, EventArgs.Empty); LogHelper.WriteLog($"Socket客户端:【{ipAddress}】连接成功!", LogTypeEnum.SocketRun); } catch (Exception ex) { LogHelper.WriteLog($"Socket服务端监听客户端的连接的函数发生异常:【{ex.Message}】", LogTypeEnum.SocketErr); } } } /// /// //该方法负责接收从客户端发送过来的数据 /// /// Socket套接字 public void RecevieMsg(object socket) { Socket newSocket = socket as Socket;//转成对应的Socket类型 string IPPortID = newSocket.RemoteEndPoint.ToString();//这个线程ID while (Flag_Listen) { byte[] buffer = new byte[1024 * 2]; int receiveLength; try //由于Socket中的Receive方法容易抛出异常,所以我们在这里要捕获异常。 { receiveLength = dicSockClientList[IPPortID].Receive(buffer);//接收从客户端发送过来的数据 } catch (Exception ex) { dicSockClientList.TryRemove(IPPortID, out Socket tryRemoveSocket); if (tryRemoveSocket != null) { tryRemoveSocket.Disconnect(false); tryRemoveSocket.Close(); } //dicSockThreadList[IPPortID].Abort(); // dicSockThreadList.TryRemove(IPPortID, out _); //newSocket.Disconnect(false); newSocket.Close(); LogHelper.WriteLog($"Socket客户端:【{IPPortID}】数据接受发生异常:【{ex.Message}】,Socket服务端已经移除该客户端连接!", LogTypeEnum.SocketErr); //触发Socket客户端断开连接实践 OnCloseEvent(IPPortID, EventArgs.Empty); break; } if (receiveLength > 0) { //记录接收到的原始数据 LogHelper.WriteLog($"Socket客户端:【{IPPortID}】接收到:【{receiveLength}】字节数据,数据内容:【{BitConverter.ToString(buffer, 0, receiveLength)}】。", LogTypeEnum.SocketData); } //触发接收到Socket客户端发送数据的事件 OnNewMessage(buffer, IPPortID, receiveLength, EventArgs.Empty); } } /// /// 关闭服务 /// public void CloseServer() { lock (dicSockClientList) { foreach (var item in dicSockClientList) { item.Value.Close();//关闭每一个连接 } dicSockClientList.Clear();//清除字典 } lock (dicSockThreadList) { foreach (var item in dicSockThreadList) { item.Value.Abort();//停止线程 } dicSockThreadList.Clear(); } Flag_Listen = false; //服务端不能主动关闭连接,需要把监听到的连接逐个关闭 //SocketServerListen.Shutdown(SocketShutdown.Both); if (SocketServerListen != null) { SocketServerListen.Close(); } } #endregion } #region 定义委托、事件 /// /// 获取消息委托 /// /// 消息主体buffer /// ip /// 数据长度 /// 事件类对象 public delegate void GetMessageEventHandler(object sender, string ip, int dataLength, EventArgs e); /// /// 获取链接委托 /// /// 链接进入的IP /// 事件类对象 public delegate void GetAcceptEventHandler(object sender, EventArgs e); /// /// 关闭链接委托 /// /// 链接进入的IP /// 事件类对象 public delegate void GetCloseEventHandler(object sender, EventArgs e); #endregion }