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
}