123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- 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
- {
- /// <summary>
- /// 先导智能Socket服务端操作帮助类
- /// Copyright20181102 (C) sunyalong
- /// 允许修改、添加满足自己项目的需要。
- /// 添加、修改后请详细注释。违者会强制删除不予采用。
- /// </summary>
- public class LeadSocketServerHelper
- {
- #region 事件
- public event GetMessageEventHandler MessageEvent;
- /// <summary>
- /// 触发接收到Socket客户端消息的委托事件
- /// </summary>
- /// <param name="sender">数据buffer</param>
- /// <param name="ip">ip</param>
- /// <param name="dataLength">数据长度</param>
- /// <param name="e">事件类对象</param>
- protected virtual void OnNewMessage(object sender, string ip, int dataLength, EventArgs e)
- {
- MessageEvent?.Invoke(sender, ip, dataLength, e);
- }
- public event GetAcceptEventHandler AcceptEvent;
- /// <summary>
- /// 触发Socket客户接入服务端的委托事件
- /// </summary>
- /// <param name="sender">链接进入的IP(Socket对象)</param>
- /// <param name="e">事件类对象</param>
- protected virtual void OnAcceptEvent(object sender, EventArgs e)
- {
- AcceptEvent?.Invoke(sender, e);
- }
- public event GetCloseEventHandler CloseEvent;
- /// <summary>
- /// 触发关闭链接委托事件
- /// </summary>
- /// <param name="sender">链接进入的IP(Socket对象)</param>
- /// <param name="e">事件类对象</param>
- protected virtual void OnCloseEvent(object sender, EventArgs e)
- {
- CloseEvent?.Invoke(sender, e);
- }
- #endregion
- #region 全局变量
- /// <summary>
- /// Socket服务端套接字对象
- /// </summary>
- public Socket SocketServerListen;
- /// <summary>
- /// Socket客户端套接字对象字典
- /// </summary>
- public ConcurrentDictionary<string, Socket> dicSockClientList = new ConcurrentDictionary<string, Socket>();
- /// <summary>
- /// Socket客户端接受数据线程字典
- /// </summary>
- public ConcurrentDictionary<string, Thread> dicSockThreadList = new ConcurrentDictionary<string, Thread>();
- /// <summary>
- /// 监听客户端连接的线程标识
- /// </summary>
- private bool Flag_Listen = false;
- #endregion
- #region 方法
- /// <summary>
- /// 开启监听
- /// </summary>
- /// <param name="ip">服务端IP地址</param>
- /// <param name="port"服务端>端口号</param>
- 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<BasBarcodeScannerMd> 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<BasBarcodeScannerMd> scannerList = allBarcodeScannerList as List<BasBarcodeScannerMd>;
- 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
- /// <summary>
- /// 循环监听客户端的连接
- /// </summary>
- 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);
- }
- }
- }
- /// <summary>
- /// //该方法负责接收从客户端发送过来的数据
- /// </summary>
- /// <param name="socket">Socket套接字</param>
- 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);
- }
- }
- /// <summary>
- /// 关闭服务
- /// </summary>
- 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 定义委托、事件
- /// <summary>
- /// 获取消息委托
- /// </summary>
- /// <param name="sender">消息主体buffer</param>
- /// <param name="ip">ip</param>
- /// <param name="dataLength">数据长度</param>
- /// <param name="e">事件类对象</param>
- public delegate void GetMessageEventHandler(object sender, string ip, int dataLength, EventArgs e);
- /// <summary>
- /// 获取链接委托
- /// </summary>
- /// <param name="sender">链接进入的IP</param>
- /// <param name="e">事件类对象</param>
- public delegate void GetAcceptEventHandler(object sender, EventArgs e);
- /// <summary>
- /// 关闭链接委托
- /// </summary>
- /// <param name="sender">链接进入的IP</param>
- /// <param name="e">事件类对象</param>
- public delegate void GetCloseEventHandler(object sender, EventArgs e);
- #endregion
- }
|