451 lines
17 KiB
C#
451 lines
17 KiB
C#
|
|
using SuperSocket.SocketBase;
|
|||
|
|
using SuperSocket.SocketBase.Protocol;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Concurrent;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Text.RegularExpressions;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
|
|||
|
|
namespace StandardDomeNewApp.Communication.Sockets
|
|||
|
|
{
|
|||
|
|
public class SingleSocketServer
|
|||
|
|
{
|
|||
|
|
public SingleSocketServer(string encoding = null)
|
|||
|
|
{
|
|||
|
|
this.encoding = string.IsNullOrEmpty(encoding) ? Encoding.Default : Encoding.GetEncoding(encoding);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 服务类型 1是supersocket 2是iocp
|
|||
|
|
/// </summary>
|
|||
|
|
private int serverType { set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 解码方式
|
|||
|
|
/// </summary>
|
|||
|
|
public Encoding encoding { private set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 服务对象
|
|||
|
|
/// </summary>
|
|||
|
|
private AppServer appServer { set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
private socket.core.Server.TcpPushServer iocpServer { set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
private Regex regex { set; get; } = new Regex(@"^%.*|.*%$");
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话字典
|
|||
|
|
/// </summary>
|
|||
|
|
public Dictionary<string, string> SessionIDDic { private set; get; } = new Dictionary<string, string>();
|
|||
|
|
/// <summary>
|
|||
|
|
/// 消息委托
|
|||
|
|
/// </summary>
|
|||
|
|
public Action<string, bool, Core.SysEnumInfon.MessageLogType> ShowMessageAction { set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 接收消息委托 二进制数组的
|
|||
|
|
/// </summary>
|
|||
|
|
public Action<string, string> RequestReceivedAction { set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话进来
|
|||
|
|
/// </summary>
|
|||
|
|
public Action<string> OnSessionAccept { set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话结束
|
|||
|
|
/// </summary>
|
|||
|
|
public Action<string> OnSessionClose { set; get; }
|
|||
|
|
public bool IsOpenServer { private set; get; }
|
|||
|
|
public string ServerName { private set; get; }
|
|||
|
|
/// <summary>
|
|||
|
|
/// 是否允许接收字典
|
|||
|
|
/// </summary>
|
|||
|
|
public ConcurrentDictionary<string, bool> IsAllowReceiveDic { set; get; } = new ConcurrentDictionary<string, bool>();
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话数据字典
|
|||
|
|
/// </summary>
|
|||
|
|
public ConcurrentDictionary<string, string> SessionDataDic { set; get; } = new ConcurrentDictionary<string, string>();
|
|||
|
|
#region 方法
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 启动服务
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="port">服务端口</param>
|
|||
|
|
/// <param name="enddata">servertype为2时才有意义 结尾符</param>
|
|||
|
|
public void StartServer(string serverkey, int port, byte[] enddata = null)
|
|||
|
|
{
|
|||
|
|
ServerName = serverkey;
|
|||
|
|
if (enddata == null)
|
|||
|
|
{
|
|||
|
|
//当为空时使用iocp的方式
|
|||
|
|
serverType = 2;
|
|||
|
|
iocpServer = new socket.core.Server.TcpPushServer(100, 1024 * 2, 0);
|
|||
|
|
if (ushort.TryParse(port.ToString(), out ushort port2))
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
iocpServer.Start(port);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("启动失败!" + ex.Message, false, Core.SysEnumInfon.MessageLogType.Warn);
|
|||
|
|
}
|
|||
|
|
IsOpenServer = true;
|
|||
|
|
iocpServer.OnAccept += IocpServer_OnAccept;
|
|||
|
|
iocpServer.OnClose += IocpServer_OnClose;
|
|||
|
|
iocpServer.OnReceive += IocpServer_OnReceive;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("端口输入范围在:0-65535的值!", false, Core.SysEnumInfon.MessageLogType.Warn);
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
//使用supersocket组件
|
|||
|
|
serverType = 1;
|
|||
|
|
if (enddata.Length < 1)
|
|||
|
|
{
|
|||
|
|
appServer = new AppServer();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
appServer = new AppServer(new TerminatorReceiveFilterFactory(encoding.GetString(enddata)));
|
|||
|
|
}
|
|||
|
|
appServer.NewRequestReceived += AppServer_NewRequestReceived;
|
|||
|
|
appServer.NewSessionConnected += AppServer_NewSessionConnected;
|
|||
|
|
appServer.SessionClosed += AppServer_SessionClosed;
|
|||
|
|
var serverconfig = new SuperSocket.SocketBase.Config.ServerConfig();
|
|||
|
|
serverconfig.Port = port;
|
|||
|
|
serverconfig.TextEncoding = encoding.EncodingName;
|
|||
|
|
if (ushort.TryParse(port.ToString(), out ushort port1))
|
|||
|
|
{
|
|||
|
|
if (!appServer.Setup(serverconfig))
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("设置错误!", false, Core.SysEnumInfon.MessageLogType.Warn);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!appServer.Start())
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("启动失败!", false, Core.SysEnumInfon.MessageLogType.Warn);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
IsOpenServer = true;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("端口输入范围在:0-65535的值!", false, Core.SysEnumInfon.MessageLogType.Warn);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 结束服务
|
|||
|
|
/// </summary>
|
|||
|
|
public void StopServer()
|
|||
|
|
{
|
|||
|
|
if (!IsOpenServer)
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("当前状态不需要断开监听!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (serverType == 1)
|
|||
|
|
{
|
|||
|
|
appServer.Stop();
|
|||
|
|
appServer.Dispose();
|
|||
|
|
appServer = null;
|
|||
|
|
}
|
|||
|
|
else if (serverType == 2)
|
|||
|
|
{
|
|||
|
|
var dic = new Dictionary<int, string>(iocpServer.ClientList);
|
|||
|
|
foreach (var item in dic)
|
|||
|
|
{
|
|||
|
|
iocpServer.Close(item.Key);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
IsOpenServer = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话发送
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="datas"></param>
|
|||
|
|
/// <param name="sessionid">为空时为广播</param>
|
|||
|
|
public void SessionSend(byte[] datas, string sessionid = null)
|
|||
|
|
{
|
|||
|
|
if (datas == null || datas.Length < 1)
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("数据为空,无效发送!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (string.IsNullOrEmpty(sessionid))
|
|||
|
|
{
|
|||
|
|
if (serverType == 1)
|
|||
|
|
{
|
|||
|
|
var allsessions = appServer.GetAllSessions();
|
|||
|
|
foreach (var item in allsessions)
|
|||
|
|
{
|
|||
|
|
item.Send(encoding.GetString(datas));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (serverType == 2)
|
|||
|
|
{
|
|||
|
|
foreach (var item in iocpServer.ClientList)
|
|||
|
|
{
|
|||
|
|
iocpServer.Send(item.Key, datas, 0, datas.Length);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (serverType == 1)
|
|||
|
|
{
|
|||
|
|
var one = appServer.GetSessionByID(sessionid);
|
|||
|
|
if (one != null)
|
|||
|
|
{
|
|||
|
|
one.Send(encoding.GetString(datas));
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("请检查传入的会话ID是否有效!当前无法查询到相关会话信息,无效发送!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (serverType == 2)
|
|||
|
|
{
|
|||
|
|
if (int.TryParse(sessionid, out int num) && iocpServer.ClientList.ContainsKey(num))
|
|||
|
|
{
|
|||
|
|
iocpServer.Send(num, datas, 0, datas.Length);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("请检查传入的会话ID是否有效!当前无法查询到相关会话信息,无效发送!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话发送
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="datas"></param>
|
|||
|
|
/// <param name="sessionid">为空时为广播</param>
|
|||
|
|
public void SessionSend(string datas, string sessionid = null)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(datas))
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("数据为空,无效发送!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (string.IsNullOrEmpty(sessionid))
|
|||
|
|
{
|
|||
|
|
if (serverType == 1)
|
|||
|
|
{
|
|||
|
|
var allsessions = appServer.GetAllSessions();
|
|||
|
|
foreach (var item in allsessions)
|
|||
|
|
{
|
|||
|
|
item.Send(datas);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (serverType == 2)
|
|||
|
|
{
|
|||
|
|
foreach (var item in iocpServer.ClientList)
|
|||
|
|
{
|
|||
|
|
iocpServer.Send(item.Key, encoding.GetBytes(datas), 0, datas.Length);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (serverType == 1)
|
|||
|
|
{
|
|||
|
|
var one = appServer.GetSessionByID(sessionid);
|
|||
|
|
if (one != null)
|
|||
|
|
{
|
|||
|
|
one.Send(datas);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("请检查传入的会话ID是否有效!当前无法查询到相关会话信息,无效发送!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (serverType == 2)
|
|||
|
|
{
|
|||
|
|
if (int.TryParse(sessionid, out int num) && iocpServer.ClientList.ContainsKey(num))
|
|||
|
|
{
|
|||
|
|
iocpServer.Send(num, encoding.GetBytes(datas), 0, datas.Length);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ShowMessageAction?.Invoke("请检查传入的会话ID是否有效!当前无法查询到相关会话信息,无效发送!", false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 返回地址对应的sessionid 可能返回为空
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="ipaddress"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public string GetSessionID(string ipaddress)
|
|||
|
|
{
|
|||
|
|
string sessionid = null;
|
|||
|
|
var datas = SessionIDDic.Where(d => d.Value == ipaddress);
|
|||
|
|
if (datas != null)
|
|||
|
|
{
|
|||
|
|
var list = datas.ToList();
|
|||
|
|
if (list.Count > 0)
|
|||
|
|
{
|
|||
|
|
var oneitem = list.ElementAt(0);
|
|||
|
|
sessionid = oneitem.Key;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return sessionid;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 返回id对应的地址 可能返回为空
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sessionid"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public string GetIpAddress(string sessionid)
|
|||
|
|
{
|
|||
|
|
if (SessionIDDic.ContainsKey(sessionid))
|
|||
|
|
{
|
|||
|
|
return SessionIDDic[sessionid];
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 事件
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话关闭
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="session"></param>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
private void AppServer_SessionClosed(AppSession session, CloseReason value)
|
|||
|
|
{
|
|||
|
|
if (SessionIDDic.ContainsKey(session.SessionID))
|
|||
|
|
{
|
|||
|
|
SessionIDDic.Remove(session.SessionID);
|
|||
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|||
|
|
stringBuilder.Append("会话:");
|
|||
|
|
stringBuilder.Append(session.SessionID);
|
|||
|
|
stringBuilder.Append("(");
|
|||
|
|
stringBuilder.Append(session.RemoteEndPoint.Address);
|
|||
|
|
stringBuilder.Append(":");
|
|||
|
|
stringBuilder.Append(session.RemoteEndPoint.Port.ToString());
|
|||
|
|
stringBuilder.Append(")");
|
|||
|
|
stringBuilder.Append("关闭!关闭原因:");
|
|||
|
|
stringBuilder.Append(value.ToString());
|
|||
|
|
ShowMessageAction?.Invoke(stringBuilder.ToString(), false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
OnSessionClose?.Invoke(session.SessionID);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void IocpServer_OnClose(int obj)
|
|||
|
|
{
|
|||
|
|
if (SessionIDDic.ContainsKey(obj.ToString()))
|
|||
|
|
{
|
|||
|
|
SessionIDDic.Remove(obj.ToString());
|
|||
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|||
|
|
stringBuilder.Append("会话:");
|
|||
|
|
stringBuilder.Append(obj.ToString());
|
|||
|
|
stringBuilder.Append("(");
|
|||
|
|
if (iocpServer.ClientList.ContainsKey(obj))
|
|||
|
|
{
|
|||
|
|
stringBuilder.Append(iocpServer.ClientList[obj]);
|
|||
|
|
}
|
|||
|
|
stringBuilder.Append(")");
|
|||
|
|
stringBuilder.Append("关闭!关闭原因:用户退出!");
|
|||
|
|
ShowMessageAction?.Invoke(stringBuilder.ToString(), false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
OnSessionClose?.Invoke(obj.ToString());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话新连接
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="session"></param>
|
|||
|
|
private void AppServer_NewSessionConnected(AppSession session)
|
|||
|
|
{
|
|||
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|||
|
|
stringBuilder.Append(session.RemoteEndPoint.Address);
|
|||
|
|
stringBuilder.Append(":");
|
|||
|
|
stringBuilder.Append(session.RemoteEndPoint.Port.ToString());
|
|||
|
|
string info = stringBuilder.ToString();
|
|||
|
|
//记录会话id与物理地址的关系
|
|||
|
|
SessionIDDic[session.SessionID] = info;
|
|||
|
|
stringBuilder.Remove(0, stringBuilder.Length);
|
|||
|
|
stringBuilder.Append("新进会话:");
|
|||
|
|
stringBuilder.Append(session.SessionID);
|
|||
|
|
stringBuilder.Append("(");
|
|||
|
|
stringBuilder.Append(info);
|
|||
|
|
stringBuilder.Append(")");
|
|||
|
|
ShowMessageAction?.Invoke(stringBuilder.ToString(), false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
OnSessionAccept?.Invoke(session.SessionID);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 新的会话进来
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="obj"></param>
|
|||
|
|
private void IocpServer_OnAccept(int obj)
|
|||
|
|
{
|
|||
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|||
|
|
if (!iocpServer.ClientList.ContainsKey(obj))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
stringBuilder.Append(iocpServer.ClientList[obj]);
|
|||
|
|
string info = stringBuilder.ToString();
|
|||
|
|
//记录会话id与物理地址的关系
|
|||
|
|
SessionIDDic[obj.ToString()] = info;
|
|||
|
|
stringBuilder.Remove(0, stringBuilder.Length);
|
|||
|
|
stringBuilder.Append("新进会话:");
|
|||
|
|
stringBuilder.Append(obj.ToString());
|
|||
|
|
stringBuilder.Append("(");
|
|||
|
|
stringBuilder.Append(info);
|
|||
|
|
stringBuilder.Append(")");
|
|||
|
|
ShowMessageAction?.Invoke(stringBuilder.ToString(), false, Core.SysEnumInfon.MessageLogType.Info);
|
|||
|
|
OnSessionAccept?.Invoke(obj.ToString());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 会话信息接收
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="session"></param>
|
|||
|
|
/// <param name="requestInfo"></param>
|
|||
|
|
private void AppServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo)
|
|||
|
|
{
|
|||
|
|
var sessionid = session.SessionID;
|
|||
|
|
var bdatas = requestInfo.Key + "%" + requestInfo.Body;
|
|||
|
|
if (string.IsNullOrEmpty(bdatas))
|
|||
|
|
{
|
|||
|
|
//空数据不解析
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (regex.IsMatch(bdatas))
|
|||
|
|
{
|
|||
|
|
//如果有%在头或者尾
|
|||
|
|
bdatas = bdatas.Replace("%", "").Trim();
|
|||
|
|
}
|
|||
|
|
RequestReceivedAction(sessionid, bdatas);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 接收消息
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="arg1"></param>
|
|||
|
|
/// <param name="arg2"></param>
|
|||
|
|
private void IocpServer_OnReceive(int arg1, byte[] arg2)
|
|||
|
|
{
|
|||
|
|
RequestReceivedAction(arg1.ToString(), encoding.GetString(arg2));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
}
|
|||
|
|
}
|