Shun 2 gadi atpakaļ
vecāks
revīzija
b91e2877b9

+ 1 - 0
README.md

@@ -32,5 +32,6 @@ S7Service
 9.事件结果统一  
 10.采集订阅流程实现多线程队列形式,处理速度大大提升  
 11.底层通信库性能提升
+12.Core: 支持HTTP、TCP客户端、TCP服务端、UDP、WS客户端、WS服务端、串口、脚本、redis、反射、自定义订阅、虚拟点
 
 

+ 4 - 9
src/YSAI.DAQ/YSAI.Core/communication/net/tcp/client/TcpClientData.cs

@@ -34,14 +34,9 @@ namespace YSAI.Core.communication.net.tcp.client
             public int ReconnectionInterval{ get; set; } = 2000;
 
             /// <summary>
-            /// 连接超时时间
+            /// 超时时间
             /// </summary>
-            public int ConnectTimeout { get; set; } = 1000;
-
-            /// <summary>
-            /// 发送超时时间
-            /// </summary>
-            public int SendTimeout { get; set; } = 1000;
+            public int Timeout { get; set; } = 1000;
 
             /// <summary>
             /// 重写基类中的Equals方法
@@ -67,8 +62,8 @@ namespace YSAI.Core.communication.net.tcp.client
                         Ip.Equals(basics.Ip) &&
                         Port.Equals(basics.Port) &&
                         InterruptReconnection.Equals(basics.InterruptReconnection) &&
-                        ConnectTimeout.Equals(basics.ConnectTimeout) &&
-                        SendTimeout.Equals(basics.SendTimeout))
+                        Timeout.Equals(basics.Timeout) &&
+                        Timeout.Equals(basics.Timeout))
                     {
                         return true;
                     }

+ 5 - 6
src/YSAI.DAQ/YSAI.Core/communication/net/tcp/client/TcpClientOperate.cs

@@ -179,7 +179,7 @@ namespace YSAI.Core.communication.net.tcp.client
             Depart("On");
             try
             {
-                //串口打开了
+                //打开了
                 if (Communication != null && Communication.Connected)
                 {
                     return Break("On", false, "已打开");
@@ -187,8 +187,8 @@ namespace YSAI.Core.communication.net.tcp.client
                 Communication = new TcpClient();
                 //设置参数
                 IPEndPoint IpPort = new IPEndPoint(IPAddress.Parse(basics.Ip), basics.Port);
-                Communication.SendTimeout = basics.SendTimeout;
-                if (!Communication.ConnectAsync(IpPort).Wait(basics.ConnectTimeout))
+                Communication.SendTimeout = basics.Timeout;
+                if (!Communication.ConnectAsync(IpPort).Wait(basics.Timeout))
                 {
                     Communication = null;
                     return Break("On", false, "连接超时");
@@ -325,12 +325,11 @@ namespace YSAI.Core.communication.net.tcp.client
                                     int bytes = Communication.GetStream().Read(Byte, 0, alen);  //读取数据
                                     if (bytes > 0)
                                     {
-                                        OnEventHandler(this, new EventResult(true, $"接收到[{ClassName}]监控数据", ByteTool.ByteTrimEnd(Byte), @enum.ResultType.Bytes));  //数据传递出去
+                                        return;
                                     }
                                     else
                                     {
-                                        OnEventHandler(this, new EventResult(false, $"接收到[{ClassName}]监控数据长度错误(小于等于零)"));  //数据传递出去
-                                        OffAsync();
+                                        Thread.Sleep(SleepTime);
                                     }
                                 }
                                 else

+ 15 - 5
src/YSAI.DAQ/YSAI.Core/communication/net/tcp/service/TcpServiceOperate.cs

@@ -47,11 +47,6 @@ namespace YSAI.Core.communication.net.tcp.service
             return exp;
         }
 
-        public void Dispose()
-        {
-            throw new NotImplementedException();
-        }
-
         /// <summary>
         /// 构造函数
         /// </summary>
@@ -337,6 +332,10 @@ namespace YSAI.Core.communication.net.tcp.service
                             return Break("Send", false, $"数据发送[{IpPort}]失败", Message, @enum.ResultType.All);
                         }
                     }
+                    else
+                    {
+                        return Break("Send", false, $"数据发送失败,[{IpPort}]不存在", Message, @enum.ResultType.All);
+                    }
                 }
                 return Break("Send", true);
             }
@@ -350,5 +349,16 @@ namespace YSAI.Core.communication.net.tcp.service
         {
             return Task.Run(() => Send(Data, Address));
         }
+
+        /// <summary>
+        /// 释放
+        /// </summary>
+        public void Dispose()
+        {
+            Off();
+            GC.Collect();
+            GC.SuppressFinalize(this);
+            ThisObjList.Remove(this);
+        }
     }
 }

+ 4 - 4
src/YSAI.DAQ/YSAI.Core/communication/net/udp/UdpOperate.cs

@@ -122,7 +122,7 @@ namespace YSAI.Core.communication.net.udp
             Depart("On");
             try
             {
-                //串口打开了
+                //打开了
                 if (Communication != null)
                 {
                     return Break("On", false, "已打开");
@@ -277,12 +277,12 @@ namespace YSAI.Core.communication.net.udp
                                     UdpReceiveResult urr = Communication.ReceiveAsync().Result;  //读取数据
                                     if (urr.Buffer.Length > 0)
                                     {
-                                        OnEventHandler(this, new EventResult(true, $"接收到[{ClassName}]监控数据,来自[{urr.RemoteEndPoint}]", new UdpData.TerminalMessage { IpPort = urr.RemoteEndPoint.ToString(), Data = ByteTool.ByteTrimEnd(urr.Buffer) }, @enum.ResultType.Bytes));  //数据传递出去
+                                        Byte = urr.Buffer;
+                                        return;
                                     }
                                     else
                                     {
-                                        OnEventHandler(this, new EventResult(false, $"接收到[{ClassName}]监控数据长度错误(小于等于零)"));  //数据传递出去
-                                        OffAsync();
+                                        Thread.Sleep(SleepTime);
                                     }
                                 }
                                 else

+ 64 - 1
src/YSAI.DAQ/YSAI.Core/communication/net/ws/client/WsClientData.cs

@@ -6,7 +6,70 @@ using System.Threading.Tasks;
 
 namespace YSAI.Core.communication.net.ws.client
 {
-    internal class WsClientData
+    public class WsClientData
     {
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        public class Basics : BasicsData
+        {
+            /// <summary>
+            /// 服务端IP
+            /// </summary>
+            public string? Ip { get; set; } = "127.0.0.1";
+            /// <summary>
+            /// 服务器端口
+            /// </summary>
+            public int Port { get; set; } = 6688;
+            /// <summary>
+            /// 是否需要断开重新连接
+            /// </summary>
+            public bool InterruptReconnection { get; set; } = true;
+            /// <summary>
+            /// 重连间隔(毫秒)
+            /// </summary>
+            public int ReconnectionInterval { get; set; } = 2000;
+
+            /// <summary>
+            /// 超时时间
+            /// </summary>
+            public int Timeout { get; set; } = 1000;
+
+            /// <summary>
+            /// 重写基类中的Equals方法
+            /// </summary>
+            /// <param name="obj"></param>
+            /// <returns></returns>
+            public override bool Equals(object obj)
+            {
+                if (obj == null)
+                {
+                    return false;
+                }
+                Basics? basics = obj as Basics;
+                if (basics == null)
+                {
+                    return false;
+                }
+                else
+                {
+                    if (SN.Equals(basics.SN) &&
+                        SendWait.Equals(basics.SendWait) &&
+                        SendWaitInterval.Equals(basics.SendWaitInterval) &&
+                        Ip.Equals(basics.Ip) &&
+                        Port.Equals(basics.Port) &&
+                        InterruptReconnection.Equals(basics.InterruptReconnection) &&
+                        Timeout.Equals(basics.Timeout) &&
+                        Timeout.Equals(basics.Timeout))
+                    {
+                        return true;
+                    }
+                    else
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
     }
 }

+ 394 - 1
src/YSAI.DAQ/YSAI.Core/communication/net/ws/client/WsClientOperate.cs

@@ -1,12 +1,405 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net.WebSockets;
 using System.Text;
 using System.Threading.Tasks;
+using YSAI.Core.data;
+using YSAI.Core.@interface;
+using YSAI.Unility;
 
 namespace YSAI.Core.communication.net.ws.client
 {
-    internal class WsClientOperate
+    public class WsClientOperate : IBaseAbstract, ICommunication
     {
+        protected override string LogHead => "[ WsClientOperate 操作 ]";
+        protected override string ClassName => "WsClientOperate";
+
+
+        private static readonly object Lock = new object();  //锁
+        private static List<WsClientOperate> ThisObjList = new List<WsClientOperate>(); //自身对象集合
+        /// <summary>
+        /// 单例模式
+        /// </summary>
+        /// <param name="basics">基础数据</param>
+        /// <returns></returns>
+        public static WsClientOperate Instance(WsClientData.Basics basics)
+        {
+            WsClientOperate? 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
+                    {
+                        WsClientOperate exp2 = new WsClientOperate(basics);
+                        ThisObjList.Add(exp2);
+                        return exp2;
+                    }
+                }
+            }
+            return exp;
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="basics">基础数据</param>
+        public WsClientOperate(WsClientData.Basics basics)
+        {
+            //设置参数
+            this.basics = basics;
+        }
+        /// <summary>
+        /// 休眠时间
+        /// </summary>
+        private int SleepTime = 10;
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        private WsClientData.Basics basics;
+        /// <summary>
+        /// 通信库
+        /// </summary>
+        private ClientWebSocket Communication;
+        /// <summary>
+        /// 监控开关 
+        /// </summary>
+        private CancellationTokenSource MonitorSwitch;
+        /// <summary>
+        /// 任务
+        /// </summary>
+        private Task MonitorTask;
+        /// <summary>
+        /// 断线重连开关
+        /// </summary>
+        private CancellationTokenSource InterruptReconnectionSwitch;
+        /// <summary>
+        /// 任务
+        /// </summary>
+        private Task InterruptReconnectionTask;
+        /// <summary>
+        /// 监控
+        /// </summary>
+        /// <returns></returns>
+        private Task Monitor(CancellationTokenSource token)
+        {
+            //起一个新线程来监控
+            return Task.Factory.StartNew(() =>
+            {
+                while (!token.IsCancellationRequested)
+                {
+                    try
+                    {
+                        if (Communication.State.Equals(WebSocketState.Open))
+                        {
+                            ArraySegment<byte> CacheBuffer = new ArraySegment<byte>();
+                            WebSocketReceiveResult result = Communication.ReceiveAsync(CacheBuffer, token.Token).Result;  //读取数据
+                            if (result.Count > 0)
+                            {
+                                OnEventHandler(this, new EventResult(true, $"接收到[{ClassName}]监控数据", ByteTool.ByteTrimEnd(CacheBuffer.Array), @enum.ResultType.Bytes));  //数据传递出去
+                            }
+                            else
+                            {
+                                OnEventHandler(this, new EventResult(false, $"接收到[{ClassName}]监控数据长度错误(小于等于零)"));  //数据传递出去
+                                OffAsync();
+                            }
+                        }
+                        else
+                        {
+                            Thread.Sleep(SleepTime);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        OnEventHandler(this, new EventResult(false, $"[{ClassName}]监控异常,关闭对象:{ex.Message}"));
+                        OffAsync();
+                    }
+                }
+            }, token.Token);
+        }
+
+        /// <summary>
+        /// 断线重连
+        /// </summary>
+        /// <returns></returns>
+        private Task InterruptReconnection(CancellationTokenSource token)
+        {
+            //起一个新线程来监控
+            return Task.Factory.StartNew(() =>
+            {
+                int ReconnectionCount = 1;
+                while (!token.IsCancellationRequested)
+                {
+                    try
+                    {
+                        if (!Communication.State.Equals(WebSocketState.Open))
+                        {
+                            if (On().State)
+                            {
+                                OnEventHandler(this, new EventResult(true, $"[{ClassName}]断线重连成功"));  //数据传递出去
+                                ReconnectionCount = 1;
+                            }
+                            else
+                            {
+                                OnEventHandler(this, new EventResult(false, $"[{ClassName}]断线重连失败,重连{ReconnectionCount}次"));  //数据传递出去
+                                ReconnectionCount++;
+                            }
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        OnEventHandler(this, new EventResult(false, $"[{ClassName}]断线重连异常:{ex.Message}"));
+                    }
+
+                    Thread.Sleep(basics.ReconnectionInterval);
+                }
+            }, token.Token);
+        }
+
+        public OperateResult On()
+        {
+            Depart("On");
+            try
+            {
+                if (Communication != null && Communication.State.Equals(WebSocketState.Open))
+                {
+                    return Break("On", false, "已打开");
+                }
+                //实例化对象
+                Communication = new ClientWebSocket();
+                //创建链接
+                Uri uri = new Uri($"ws://{basics.Ip}:{basics.Port}");
+                //连接
+                if (!Communication.ConnectAsync(uri, CancellationToken.None).Wait(basics.Timeout))
+                {
+                    Communication = null;
+                    return Break("On", false, "连接超时");
+                }
+                //断线重连
+                if (basics.InterruptReconnection)
+                {
+                    //监控开关
+                    if (InterruptReconnectionSwitch == null || InterruptReconnectionSwitch.IsCancellationRequested)
+                    {
+                        InterruptReconnectionSwitch = new CancellationTokenSource();
+                    }
+                    //监控
+                    InterruptReconnectionTask = InterruptReconnection(InterruptReconnectionSwitch);
+                }
+
+
+                //当使用发送等待,则不启用监控
+                if (!basics.SendWait)
+                {
+                    //监控开关
+                    if (MonitorSwitch == null || MonitorSwitch.IsCancellationRequested)
+                    {
+                        MonitorSwitch = new CancellationTokenSource();
+                    }
+                    //监控
+                    MonitorTask = Monitor(MonitorSwitch);
+                }
+
+                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 && Communication.State.Equals(WebSocketState.Open))
+                {
+                    //关闭监控
+                    if (MonitorSwitch != null)
+                    {
+                        MonitorSwitch.Cancel();
+                        //等待完成
+                        MonitorTask.Wait();
+                        //监控开关清空
+                        MonitorSwitch = null;
+                        //任务对象清空
+                        MonitorTask = null;
+                    }
+                    //关闭监控
+                    if (InterruptReconnectionSwitch != null)
+                    {
+                        InterruptReconnectionSwitch.Cancel();
+                        //等待完成
+                        InterruptReconnectionTask.Wait();
+                        //监控开关清空
+                        InterruptReconnectionSwitch = null;
+                        //任务对象清空
+                        InterruptReconnectionTask = null;
+                    }
+                    if (Communication.CloseAsync(WebSocketCloseStatus.Empty, "手动关闭", CancellationToken.None).Wait(basics.Timeout))
+                    {
+                        Communication.Dispose();
+                        Communication = null;
+                        return Break("Off", true);
+                    }
+                    else
+                    {
+                        return Break("Off", false,"关闭超时");
+                    }
+                }
+                return Break("Off", false, "未连接");
+            }
+            catch (Exception ex)
+            {
+                return Break("Off", false, ex.Message, Exc: ex);
+            }
+        }
+
+        public Task<OperateResult> OffAsync()
+        {
+            return Task.Run(() => Off());
+        }
+
+        public OperateResult Send(byte[] Data)
+        {
+            Depart("Send");
+            try
+            {
+                if (Communication != null && Communication.State.Equals(WebSocketState.Open))
+                {
+                    ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Data);
+                    if (Communication.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None).Wait(basics.Timeout))
+                    {
+                        return Break("Send", true);
+                    }
+                    return Break("Send", false, "发送数据超时");
+                }
+                return Break("Send", false, "未连接");
+            }
+            catch (Exception ex)
+            {
+                return Break("Send", false, ex.Message, Exc: ex);
+            }
+        }
+
+        public Task<OperateResult> SendAsync(byte[] Data)
+        {
+            return Task.Run(() => Send(Data));
+        }
+
+        public OperateResult SendWait(byte[] Data)
+        {
+            Depart("SendWait");
+            try
+            {
+                if (Communication != null && Communication.State.Equals(WebSocketState.Open))
+                {
+                    OperateResult reverseBack = Send(Data);
+                    if (reverseBack.State)
+                    {
+                        CancellationTokenSource token = new CancellationTokenSource();
+                        byte[] Byte = new byte[] { };
+                        bool Status = Task.Run(() =>
+                        {
+                            while (!token.IsCancellationRequested)
+                            {
+                                ArraySegment<byte> CacheBuffer = new ArraySegment<byte>();
+                                WebSocketReceiveResult result = Communication.ReceiveAsync(CacheBuffer, token.Token).Result;  //读取数据
+                                if (result.Count > 0)
+                                {
+                                    Byte = CacheBuffer.Array;
+                                    return;
+                                }
+                                else
+                                {
+                                   Thread.Sleep(SleepTime);
+                                }
+                            }
+                        }, token.Token).Wait(basics.SendWaitInterval);
+                        if (Status)
+                        {
+                            if (Byte.Length > 0)
+                            {
+                                return Break("SendWait", true, RData: Byte, RType: @enum.ResultType.Bytes);
+                            }
+                            else
+                            {
+                                return Break("SendWait", false, "未接收到数据");
+                            }
+                        }
+                        else
+                        {
+                            return Break("SendWait", false, "接收数据超时");
+                        }
+                    }
+                    return Break("SendWait", false, "读取或写入失败");
+                }
+                return Break("SendWait", false, "未连接");
+            }
+            catch (Exception ex)
+            {
+                return Break("SendWait", false, ex.Message, Exc: ex);
+            }
+        }
+
+        public Task<OperateResult> SendWaitAsync(byte[] Data)
+        {
+            return Task.Run(() => SendWait(Data));
+        }
+
+        public OperateResult GetObject()
+        {
+            Depart("GetObject");
+            if (Communication != null && Communication.State.Equals(WebSocketState.Open))
+            {
+                return Break("GetObject", true, RData: Communication, RType: @enum.ResultType.All);
+            }
+            return Break("GetObject", false, "未连接");
+        }
+
+        public Task<OperateResult> GetObjectAsync()
+        {
+            return Task.Run(() => GetObject());
+        }
+
+        public OperateResult GetStatus()
+        {
+            Depart("GetStatus");
+            if (Communication != null && Communication.State.Equals(WebSocketState.Open))
+            {
+                return Break("GetStatus", true, "已连接");
+            }
+            else
+            {
+                return Break("GetStatus", false, "未连接");
+            }
+        }
+
+        public Task<OperateResult> GetStatusAsync()
+        {
+            return Task.Run(() => GetStatus());
+        }
+
+        /// <summary>
+        /// 释放
+        /// </summary>
+        public void Dispose()
+        {
+            Off();
+            GC.Collect();
+            GC.SuppressFinalize(this);
+            ThisObjList.Remove(this);
+        }
     }
 }

+ 79 - 1
src/YSAI.DAQ/YSAI.Core/communication/net/ws/service/WsServiceData.cs

@@ -6,7 +6,85 @@ using System.Threading.Tasks;
 
 namespace YSAI.Core.communication.net.ws.service
 {
-    internal class WsServiceData
+    public class WsServiceData
     {
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        public class Basics
+        {
+            /// <summary>
+            /// 唯一标识符
+            /// </summary>
+            public string? SN { get; set; } = Guid.NewGuid().ToString();
+            /// <summary>
+            /// IP
+            /// </summary>
+            public string? Ip { get; set; } = "127.0.0.1";
+            /// <summary>
+            /// 端口
+            /// </summary>
+            public int Port { get; set; } = 6688;
+
+            /// <summary>
+            /// 重写基类中的Equals方法
+            /// </summary>
+            /// <param name="obj"></param>
+            /// <returns></returns>
+            public override bool Equals(object obj)
+            {
+                if (obj == null)
+                {
+                    return false;
+                }
+                Basics? Obj = obj as Basics;
+                if (Obj == null)
+                {
+                    return false;
+                }
+                else
+                {
+                    if (Ip == Obj.Ip &&
+                        MaxNumber == Obj.MaxNumber &&
+                         SN == Obj.SN &&
+                    Port == Obj.Port)
+                    {
+                        return true;
+                    }
+                    else
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 客户端消息
+        /// </summary>
+        public class ClientMessage
+        {
+            /// <summary>
+            /// 步骤
+            /// </summary>
+            public Steps Step { get; set; }
+            /// <summary>
+            /// IP地址:端口
+            /// </summary>
+            public string IpPort { get; set; }
+            /// <summary>
+            /// 字节数据
+            /// </summary>
+            public byte[]? Data { get; set; } = null;
+        }
+
+        /// <summary>
+        /// 步骤枚举
+        /// </summary>
+        public enum Steps
+        {
+            客户端连接,
+            客户端断开,
+            消息接收
+        }
     }
 }

+ 375 - 6
src/YSAI.DAQ/YSAI.Core/communication/net/ws/service/WsServiceOperate.cs

@@ -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);
+        }
     }
 }

+ 13 - 3
src/YSAI.DAQ/YSAI.Core/communication/serial/SerialOperate.cs

@@ -97,8 +97,15 @@ namespace YSAI.Core.communication.serial
                             if (BufSize > 0)
                             {
                                 byte[] Byte = new byte[BufSize];
-                                Communication.Read(Byte, 0, BufSize);
-                                OnEventHandler(this, new EventResult(true, $"接收到[{ClassName}]监控数据", ByteTool.ByteTrimEnd(Byte), ResultType.Bytes));
+                                if (Communication.Read(Byte, 0, BufSize) > 0)
+                                {
+                                    OnEventHandler(this, new EventResult(true, $"接收到[{ClassName}]监控数据", ByteTool.ByteTrimEnd(Byte), ResultType.Bytes));
+                                }
+                                else
+                                {
+                                    OnEventHandler(this, new EventResult(false, $"接收到[{ClassName}]监控数据长度错误(小于等于零)"));  //数据传递出去
+                                    OffAsync();
+                                }
                             }
                             else
                             {
@@ -256,7 +263,10 @@ namespace YSAI.Core.communication.serial
                                 if (BufSize > 0)
                                 {
                                     Byte = new byte[BufSize];
-                                    Communication.Read(Byte, 0, BufSize);
+                                    if (Communication.Read(Byte, 0, BufSize) <= 0)
+                                    {
+                                        Thread.Sleep(SleepTime);
+                                    }
                                 }
                                 else
                                 {

+ 34 - 0
src/YSAI.DAQ/YSAI.Test.Console/Program.cs

@@ -3,10 +3,12 @@ using Microsoft.Extensions.Primitives;
 using NModbus.Utility;
 using Org.BouncyCastle.Utilities;
 using S7.Net;
+using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Text;
 using System.Text.RegularExpressions;
+using YSAI.Core.communication.serial;
 using YSAI.Core.data;
 using YSAI.Core.@enum;
 using YSAI.Core.reflection;
@@ -26,6 +28,38 @@ using YSAI.Unility;
 using ZstdSharp.Unsafe;
 using static YSAI.Modbus.client.ModbusClientData;
 
+
+
+
+//SerialOperate serialOperate = SerialOperate.Instance(new SerialData.Basics 
+//{
+//    BaudRate=9600,
+//    DataBit=8,
+//    ParityBit=System.IO.Ports.Parity.None,
+//    PortName="COM2",
+//    StopBit=System.IO.Ports.StopBits.One
+//});
+
+//byte[] bytes = new byte[] { };
+
+//if (serialOperate.On().State)
+//{
+//    serialOperate.OnEvent += SerialOperate_OnEvent;
+//}
+//while (true)
+//{
+//    Console.ReadLine();
+//    Console.WriteLine(Encoding.Default.GetString(bytes));
+//    bytes = new byte[] { };
+//}
+
+//void SerialOperate_OnEvent(object? sender, EventResult e)
+//{
+//    byte[] array = (byte[])e.RData;
+//    Console.WriteLine(ByteTool.HexToStr(array).ToUpper());
+//    bytes = ByteTool.CombineBytes(bytes, 0, bytes.Length, array, 0, array.Length);
+//}
+
 Console.WriteLine();
 //Console.WriteLine(Guid.NewGuid().ToString().Replace("-", string.Empty).Trim().ToUpper());