|
|
@@ -1,12 +1,381 @@
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.Linq;
|
|
|
-using System.Text;
|
|
|
-using System.Threading.Tasks;
|
|
|
+using System.Collections.Concurrent;
|
|
|
+using System.Net;
|
|
|
+using System.Net.WebSockets;
|
|
|
+using YSAI.Core.data;
|
|
|
+using YSAI.Core.@interface;
|
|
|
|
|
|
namespace YSAI.Core.communication.net.ws.service
|
|
|
{
|
|
|
- internal class WsServiceOperate
|
|
|
+ public class WsServiceOperate : IBaseAbstract, IOn, IOff, IDisposable
|
|
|
{
|
|
|
+ protected override string LogHead => "[ WsServiceOperate 操作 ]";
|
|
|
+ protected override string ClassName => "WsServiceOperate";
|
|
|
+
|
|
|
+
|
|
|
+ private static readonly object Lock = new object(); //锁
|
|
|
+ private static List<WsServiceOperate> ThisObjList = new List<WsServiceOperate>(); //自身对象集合
|
|
|
+ /// <summary>
|
|
|
+ /// 单例模式
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="basics">基础数据</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static WsServiceOperate Instance(WsServiceData.Basics basics)
|
|
|
+ {
|
|
|
+ WsServiceOperate? exp = ThisObjList.FirstOrDefault(c => c.basics.Equals(basics));
|
|
|
+ if (exp == null)
|
|
|
+ {
|
|
|
+ lock (Lock)
|
|
|
+ {
|
|
|
+ if (ThisObjList.Count(c => c.basics.Equals(basics)) > 0)
|
|
|
+ {
|
|
|
+ return ThisObjList.First(c => c.basics.Equals(basics));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ WsServiceOperate exp2 = new WsServiceOperate(basics);
|
|
|
+ ThisObjList.Add(exp2);
|
|
|
+ return exp2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return exp;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 构造函数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="basics">基础数据</param>
|
|
|
+ public WsServiceOperate(WsServiceData.Basics basics)
|
|
|
+ {
|
|
|
+ //设置参数
|
|
|
+ this.basics = basics;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 休眠时间
|
|
|
+ /// </summary>
|
|
|
+ private int SleepTime = 10;
|
|
|
+ /// <summary>
|
|
|
+ /// 基础数据
|
|
|
+ /// </summary>
|
|
|
+ private WsServiceData.Basics basics;
|
|
|
+ /// <summary>
|
|
|
+ /// 通信库
|
|
|
+ /// </summary>
|
|
|
+ private HttpListener Communication;
|
|
|
+ /// <summary>
|
|
|
+ /// 监控开关
|
|
|
+ /// </summary>
|
|
|
+ private CancellationTokenSource MonitorConnectSwitch;
|
|
|
+ /// <summary>
|
|
|
+ /// 任务
|
|
|
+ /// </summary>
|
|
|
+ private Task MonitorConnectTask;
|
|
|
+ /// <summary>
|
|
|
+ /// 客户端数据
|
|
|
+ /// </summary>
|
|
|
+ class Client
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// 客户端任务对象
|
|
|
+ /// </summary>
|
|
|
+ public Task TaskObj { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 开关
|
|
|
+ /// </summary>
|
|
|
+ public CancellationTokenSource Switch { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// websocket对象
|
|
|
+ /// </summary>
|
|
|
+ public WebSocketContext WebSocketObj { get; set; }
|
|
|
+
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 客户端消息任务容器
|
|
|
+ /// </summary>
|
|
|
+ ConcurrentDictionary<string, Client> ClientIoc = new ConcurrentDictionary<string, Client>();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 监控连接
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private Task MonitorConnect(CancellationTokenSource token)
|
|
|
+ {
|
|
|
+ //起一个新线程来监控
|
|
|
+ return Task.Factory.StartNew(() =>
|
|
|
+ {
|
|
|
+ while (!token.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ HttpListenerContext httpListenerContext = Communication.GetContextAsync().Result;
|
|
|
+ if (httpListenerContext.Request.IsWebSocketRequest) // 如果是websocket请求
|
|
|
+ {
|
|
|
+ string IpPort = httpListenerContext.Request.RemoteEndPoint.Address.ToString();
|
|
|
+ try
|
|
|
+ {
|
|
|
+ WebSocketContext webSocketContext = httpListenerContext.AcceptWebSocketAsync(subProtocol: null).Result;
|
|
|
+ if (!ClientIoc.ContainsKey(IpPort)) //当字典中没有这个连接对象
|
|
|
+ {
|
|
|
+ CancellationTokenSource token = new CancellationTokenSource();
|
|
|
+ Client client = new Client
|
|
|
+ {
|
|
|
+ WebSocketObj = webSocketContext,
|
|
|
+ Switch = token,
|
|
|
+ TaskObj = MonitorMessageTask(token, webSocketContext)
|
|
|
+ };
|
|
|
+ //把此对象添加到字典中
|
|
|
+ ClientIoc.AddOrUpdate(IpPort, client, (k, v) => client);
|
|
|
+ OnEventHandler(this, new EventResult(true, $"[{IpPort}]连接成功", new WsServiceData.ClientMessage { Step = WsServiceData.Steps.客户端连接, IpPort = IpPort }, @enum.ResultType.String));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ httpListenerContext.Response.StatusCode = 500;
|
|
|
+ httpListenerContext.Response.Close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ httpListenerContext.Response.StatusCode = 400;
|
|
|
+ httpListenerContext.Response.Close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ OnEventHandler(this, new EventResult(false, $"[{ClassName}]监控客户端连接异常:{ex.Message}"));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }, token.Token);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 监控消息任务
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="token"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private Task MonitorMessageTask(CancellationTokenSource token, WebSocketContext webSocket)
|
|
|
+ {
|
|
|
+ //起一个新线程来监控
|
|
|
+ return Task.Factory.StartNew(() =>
|
|
|
+ {
|
|
|
+ string IpPort = $"{webSocket.RequestUri.Authority}:{webSocket.RequestUri.Port}";
|
|
|
+ ArraySegment<byte> DataByte = new ArraySegment<byte>(); //数据缓冲区
|
|
|
+ while (!token.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ WebSocketReceiveResult result = webSocket.WebSocket.ReceiveAsync(DataByte, token.Token).Result; // 接收数据,并返回数据的长度;
|
|
|
+ if (result.Count > 0)
|
|
|
+ {
|
|
|
+ OnEventHandler(this, new EventResult(true, $"[{IpPort}]数据接收成功", new WsServiceData.ClientMessage { Step = WsServiceData.Steps.消息接收, IpPort = IpPort, Data = DataByte.Array }, @enum.ResultType.Bytes));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ OnEventHandler(this, new EventResult(false, $"[{IpPort}]发来的数据长度错误(小于等于零),已强制关闭连接", new WsServiceData.ClientMessage { Step = WsServiceData.Steps.客户端断开, IpPort = IpPort }, @enum.ResultType.All));
|
|
|
+ //移除此客户端
|
|
|
+ RemoveAsync(IpPort);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ OnEventHandler(this, new EventResult(false, $"监控[{IpPort}]消息异常:{ex.Message}", new WsServiceData.ClientMessage { Step = WsServiceData.Steps.客户端断开, IpPort = IpPort }, @enum.ResultType.All));
|
|
|
+ //移除此客户端
|
|
|
+ RemoveAsync(IpPort);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, token.Token);
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult On()
|
|
|
+ {
|
|
|
+ Depart("On");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //串口打开了
|
|
|
+ if (Communication != null)
|
|
|
+ {
|
|
|
+ return Break("On", false, "已打开");
|
|
|
+ }
|
|
|
+ //监控开关
|
|
|
+ if (MonitorConnectSwitch == null || MonitorConnectSwitch.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ MonitorConnectSwitch = new CancellationTokenSource();
|
|
|
+ }
|
|
|
+ //监控
|
|
|
+ MonitorConnectTask = MonitorConnect(MonitorConnectSwitch);
|
|
|
+
|
|
|
+ return Break("On", true);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break("On", false, ex.Message, Exc: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> OnAsync()
|
|
|
+ {
|
|
|
+ return Task.Run(() => On());
|
|
|
+ }
|
|
|
+
|
|
|
+ public OperateResult Off()
|
|
|
+ {
|
|
|
+ Depart("Off");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (Communication != null)
|
|
|
+ {
|
|
|
+ //关闭监控
|
|
|
+ if (MonitorConnectSwitch != null)
|
|
|
+ {
|
|
|
+ MonitorConnectSwitch.Cancel();
|
|
|
+ //等待完成
|
|
|
+ MonitorConnectTask.Wait();
|
|
|
+ //监控开关清空
|
|
|
+ MonitorConnectSwitch = null;
|
|
|
+ //任务对象清空
|
|
|
+ MonitorConnectTask = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ //关闭客户端消息线程
|
|
|
+ foreach (var item in ClientIoc)
|
|
|
+ {
|
|
|
+ item.Value.Switch.Cancel();
|
|
|
+ item.Value.TaskObj.Wait();
|
|
|
+ item.Value.WebSocketObj.WebSocket.CloseAsync(WebSocketCloseStatus.Empty,"手动关闭",CancellationToken.None);
|
|
|
+ item.Value.WebSocketObj.WebSocket.Abort();
|
|
|
+ item.Value.WebSocketObj.WebSocket.Dispose();
|
|
|
+ }
|
|
|
+ //清空
|
|
|
+ ClientIoc.Clear();
|
|
|
+ Communication.Stop();
|
|
|
+ Communication.Close();
|
|
|
+ Communication = null;
|
|
|
+
|
|
|
+ return Break("Off", true);
|
|
|
+ }
|
|
|
+ return Break("Off", false, "未连接");
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break("Off", false, ex.Message, Exc: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> OffAsync()
|
|
|
+ {
|
|
|
+ return Task.Run(() => Off());
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 移除异常客户端
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public OperateResult Remove(string? IpPort)
|
|
|
+ {
|
|
|
+ //开始记录运行时间
|
|
|
+ Depart("Remove");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (ClientIoc.ContainsKey(IpPort))
|
|
|
+ {
|
|
|
+ ClientIoc[IpPort].Switch.Cancel();
|
|
|
+ ClientIoc[IpPort].TaskObj.Wait();
|
|
|
+ ClientIoc[IpPort].WebSocketObj.WebSocket.CloseAsync(WebSocketCloseStatus.Empty, "客户端连接异常", CancellationToken.None);
|
|
|
+ ClientIoc[IpPort].WebSocketObj.WebSocket.Abort();
|
|
|
+ ClientIoc[IpPort].WebSocketObj.WebSocket.Dispose();
|
|
|
+
|
|
|
+ return Break("Remove", true);
|
|
|
+ }
|
|
|
+ return Break("Remove", false, "Ip Port 不存在");
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break("Remove", false, ex.Message, Exc: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 移除异常客户端
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public Task<OperateResult> RemoveAsync(string? Key)
|
|
|
+ {
|
|
|
+ return Task.Run(() => RemoveAsync(Key));
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 数据发送
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="Data">字节数据</param>
|
|
|
+ /// <param name="IpPort">地址</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public OperateResult Send(byte[] Data, string? IpPort = null)
|
|
|
+ {
|
|
|
+ Depart("Send");
|
|
|
+ try
|
|
|
+ {
|
|
|
+ List<string> Message = new List<string>();
|
|
|
+ if (string.IsNullOrEmpty(IpPort))
|
|
|
+ {
|
|
|
+ //群发
|
|
|
+ foreach (var client in ClientIoc)
|
|
|
+ {
|
|
|
+ string IP = $"{client.Value.WebSocketObj.RequestUri.Authority}:{client.Value.WebSocketObj.RequestUri.Port}";
|
|
|
+ try
|
|
|
+ {
|
|
|
+ client.Value.WebSocketObj.WebSocket.SendAsync(new ArraySegment<byte>(Data), WebSocketMessageType.Text, true, CancellationToken.None);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ Message.Add($"[{IP}]数据发送异常:{ex.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Message.Count > 0)
|
|
|
+ {
|
|
|
+ return Break("Send", false, "存在失败数据", Message, @enum.ResultType.All);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //指定发送
|
|
|
+ if (ClientIoc.ContainsKey(IpPort))
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ ClientIoc[IpPort].WebSocketObj.WebSocket.SendAsync(new ArraySegment<byte>(Data), WebSocketMessageType.Text, true, CancellationToken.None);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break("Send", false, $"数据发送[{IpPort}]异常:{ex.Message}", Message, @enum.ResultType.All);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return Break("Send", false, $"数据发送失败,[{IpPort}]不存在", Message, @enum.ResultType.All);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Break("Send", true);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ return Break("Send", false, ex.Message, Exc: ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<OperateResult> SendAsync(byte[] Data, string? Address = null)
|
|
|
+ {
|
|
|
+ return Task.Run(() => Send(Data, Address));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 释放
|
|
|
+ /// </summary>
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ Off();
|
|
|
+ GC.Collect();
|
|
|
+ GC.SuppressFinalize(this);
|
|
|
+ ThisObjList.Remove(this);
|
|
|
+ }
|
|
|
}
|
|
|
}
|