From fcb463348c983fda168bd595549bdb0939349f67 Mon Sep 17 00:00:00 2001 From: parallelbgls Date: Tue, 26 Dec 2017 15:08:02 +0800 Subject: [PATCH] 2017-12-26 Update 1 Controller and Connector Fix --- Modbus.Net/Modbus.Net/BaseConnector.cs | 122 ++++++++++++++++++----- Modbus.Net/Modbus.Net/ComConnector.cs | 81 +++++++-------- Modbus.Net/Modbus.Net/FifoController.cs | 20 ++-- Modbus.Net/Modbus.Net/IConnector.cs | 2 +- Modbus.Net/Modbus.Net/MatchController.cs | 14 ++- Modbus.Net/Modbus.Net/TcpConnector.cs | 74 +++----------- 6 files changed, 168 insertions(+), 145 deletions(-) diff --git a/Modbus.Net/Modbus.Net/BaseConnector.cs b/Modbus.Net/Modbus.Net/BaseConnector.cs index 85c5792..b14b680 100644 --- a/Modbus.Net/Modbus.Net/BaseConnector.cs +++ b/Modbus.Net/Modbus.Net/BaseConnector.cs @@ -1,12 +1,102 @@ -using System.Threading.Tasks; +using System; +using System.Threading; +using System.Threading.Tasks; +using Nito.AsyncEx; +using Serilog; namespace Modbus.Net { - /// - /// 基础的协议连接类 - /// + /// public abstract class BaseConnector : BaseConnector { + /// + /// 发送锁 + /// + protected abstract AsyncLock Lock { get; } + + /// + /// 是否为全双工 + /// + public bool IsFullDuplex { get; } + + /// + /// 发送超时时间 + /// + protected abstract int TimeoutTime { get; set; } + + /// + /// 构造器 + /// + /// 发送超时时间 + /// 是否为全双工 + protected BaseConnector(int timeoutTime = 10000, bool isFullDuplex = true) + { + IsFullDuplex = isFullDuplex; + TimeoutTime = timeoutTime; + } + + /// + public override async Task SendMsgAsync(byte[] message) + { + var ans = await SendMsgCtrl(message); + return ans?.ReceiveMessage; + } + + /// + /// 发送主控 + /// + /// 发送的信息 + /// 等待信息的定义 + protected async Task SendMsgCtrl(byte[] message) + { + MessageWaitingDef ans; + if (!IsFullDuplex) + { + using (await Lock.LockAsync()) + { + ans = await SendMsgInner(message); + } + } + else + { + ans = await SendMsgInner(message); + } + return ans; + } + + /// + /// 发送内部 + /// + /// 发送的信息 + /// 发送信息的定义 + protected async Task SendMsgInner(byte[] message) + { + try + { + var messageSendingdef = Controller.AddMessage(message); + if (messageSendingdef != null) + { + var success = messageSendingdef.SendMutex.WaitOne(TimeoutTime); + if (success) + { + await SendMsgWithoutConfirm(message); + success = messageSendingdef.ReceiveMutex.WaitOne(TimeoutTime); + if (success) + { + return messageSendingdef; + } + } + Controller.ForceRemoveWaitingMessage(messageSendingdef); + } + return null; + } + catch (Exception e) + { + Log.Error(e, "Connector {0} Send Error.", ConnectionToken); + return null; + } + + } } /// @@ -32,33 +122,19 @@ namespace Modbus.Net /// protected virtual IController Controller { get; set; } - /// - /// 标识Connector的连接关键字 - /// + /// public abstract string ConnectionToken { get; } - /// - /// 是否处于连接状态 - /// + /// public abstract bool IsConnected { get; } - /// - /// 连接PLC,异步 - /// - /// 是否连接成功 + /// public abstract Task ConnectAsync(); - /// - /// 断开PLC - /// - /// 是否断开成功 + /// public abstract bool Disconnect(); - /// - /// 带返回发送数据 - /// - /// 需要发送的数据 - /// 是否发送成功 + /// public abstract Task SendMsgAsync(TParamIn message); /// diff --git a/Modbus.Net/Modbus.Net/ComConnector.cs b/Modbus.Net/Modbus.Net/ComConnector.cs index 1f35cc2..0da1861 100644 --- a/Modbus.Net/Modbus.Net/ComConnector.cs +++ b/Modbus.Net/Modbus.Net/ComConnector.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO.Ports; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Nito.AsyncEx; @@ -57,17 +55,29 @@ namespace Modbus.Net /// private readonly StopBits _stopBits; + /// + protected override int TimeoutTime { get; set; } + /// - /// 超时时间 + /// 错误次数 /// - private readonly int _timeoutTime; - private int _errorCount; + /// + /// 获取次数 + /// private int _receiveCount; - + /// + /// 发送次数 + /// private int _sendCount; + /// + /// 获取线程 + /// private Task _receiveThread; + /// + /// 获取线程关闭 + /// private bool _taskCancel = false; /// @@ -84,12 +94,11 @@ namespace Modbus.Net /// 停止位 /// 数据位 /// 超时时间 - public ComConnector(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits, int timeoutTime) + /// 是否为全双工 + public ComConnector(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits, int timeoutTime = 10000, bool isFullDuplex = false) : base(timeoutTime, isFullDuplex) { //端口号 _com = com.Split(':')[0]; - //读超时 - _timeoutTime = timeoutTime; //波特率 _baudRate = baudRate; //奇偶校验 @@ -108,6 +117,9 @@ namespace Modbus.Net private static Dictionary Connectors { get; } = new Dictionary() ; + /// + /// 连接中的连接器 + /// private static Dictionary Controllers { get; } = new Dictionary() ; @@ -130,6 +142,9 @@ namespace Modbus.Net } } + /// + protected override AsyncLock Lock => SerialPort.Lock; + /// /// 连接中的连接器 /// @@ -140,6 +155,9 @@ namespace Modbus.Net /// public override string ConnectionToken => _slave + ":" + _com; + /// + /// 获取当前连接器使用的串口 + /// private SerialPortLock SerialPort { get @@ -150,9 +168,7 @@ namespace Modbus.Net } } - /// - /// 实现IDisposable接口 - /// + /// public void Dispose() { Dispose(true); @@ -292,8 +308,6 @@ namespace Modbus.Net Log.Verbose("Com client {ConnectionToken} error count: {ErrorCount}", ConnectionToken, _errorCount); } - #region 发送接收数据 - /// public override bool IsConnected { @@ -324,7 +338,7 @@ namespace Modbus.Net Parity = _parity, StopBits = _stopBits, DataBits = _dataBits, - ReadTimeout = _timeoutTime + ReadTimeout = TimeoutTime }); } if (!Linkers.ContainsKey(_slave)) @@ -379,16 +393,18 @@ namespace Modbus.Net return false; } + #region 发送接收数据 + /// /// 带返回发送数据 /// /// 需要发送的数据 /// 是否发送成功 - public string SendMsg(string sendStr) + public async Task SendMsgAsync(string sendStr) { var myByte = sendStr.StringToByte_2(); - var returnBytes = SendMsg(myByte); + var returnBytes = await SendMsgAsync(myByte); return returnBytes.ByteToString(); } @@ -421,40 +437,11 @@ namespace Modbus.Net } } - /// - /// 发送数据,需要返回 - /// - /// 发送的数据 - /// 是否发送成功 - protected byte[] SendMsg(byte[] message) - { - return AsyncHelper.RunSync(() => SendMsgAsync(message)); - } - /// public override async Task SendMsgAsync(byte[] message) { CheckOpen(); - var task = SendMsgInner(message).WithCancellation(new CancellationTokenSource(100000).Token); - var ans = await task; - if (task.IsCanceled) - { - Controller.ForceRemoveWaitingMessage(ans); - return null; - } - return ans.ReceiveMessage; - } - - private async Task SendMsgInner(byte[] message) - { - using (await SerialPort.Lock.LockAsync()) - { - var messageSendingdef = Controller.AddMessage(message); - messageSendingdef.SendMutex.WaitOne(); - await SendMsgWithoutConfirm(message); - messageSendingdef.ReceiveMutex.WaitOne(); - return messageSendingdef; - } + return await base.SendMsgAsync(message); } /// diff --git a/Modbus.Net/Modbus.Net/FifoController.cs b/Modbus.Net/Modbus.Net/FifoController.cs index bb4c99d..0b8267b 100644 --- a/Modbus.Net/Modbus.Net/FifoController.cs +++ b/Modbus.Net/Modbus.Net/FifoController.cs @@ -44,19 +44,17 @@ namespace Modbus.Net } lock (WaitingMessages) { - if (_currentSendingPos == null) - { - if (WaitingMessages.Count > 0) - { - _currentSendingPos = WaitingMessages.First(); - } - } if (_currentSendingPos != null) { - _currentSendingPos.SendMutex.Set(); - _currentSendingPos = WaitingMessages.Count <= 1 - ? null - : WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; + if (WaitingMessages.Count <= 0) + { + _currentSendingPos = null; + } + if (WaitingMessages.Count > WaitingMessages.IndexOf(_currentSendingPos) + 1) + { + _currentSendingPos = WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; + _currentSendingPos.SendMutex.Set(); + } } } } diff --git a/Modbus.Net/Modbus.Net/IConnector.cs b/Modbus.Net/Modbus.Net/IConnector.cs index 121ec4b..d570a3a 100644 --- a/Modbus.Net/Modbus.Net/IConnector.cs +++ b/Modbus.Net/Modbus.Net/IConnector.cs @@ -5,7 +5,7 @@ namespace Modbus.Net /// /// Эӽӿ /// - public interface IConnector + public interface IConnector { /// /// ʶConnectorӹؼ diff --git a/Modbus.Net/Modbus.Net/MatchController.cs b/Modbus.Net/Modbus.Net/MatchController.cs index 8fed36a..a4f00f5 100644 --- a/Modbus.Net/Modbus.Net/MatchController.cs +++ b/Modbus.Net/Modbus.Net/MatchController.cs @@ -56,14 +56,20 @@ namespace Modbus.Net if (WaitingMessages.Count > 0) { _currentSendingPos = WaitingMessages.First(); + _currentSendingPos.SendMutex.Set(); } } if (_currentSendingPos != null) { - _currentSendingPos.SendMutex.Set(); - _currentSendingPos = WaitingMessages.Count <= 1 - ? null - : WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; + if (WaitingMessages.Count <= 0) + { + _currentSendingPos = null; + } + if (WaitingMessages.Count > WaitingMessages.IndexOf(_currentSendingPos) + 1) + { + _currentSendingPos = WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1]; + _currentSendingPos.SendMutex.Set(); + } } } } diff --git a/Modbus.Net/Modbus.Net/TcpConnector.cs b/Modbus.Net/Modbus.Net/TcpConnector.cs index b55234a..bdcbe9b 100644 --- a/Modbus.Net/Modbus.Net/TcpConnector.cs +++ b/Modbus.Net/Modbus.Net/TcpConnector.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using Nito.AsyncEx; using Serilog; namespace Modbus.Net @@ -61,22 +62,17 @@ namespace Modbus.Net /// Ip地址 /// 端口 /// 超时时间 - public TcpConnector(string ipaddress, int port, int timeoutTime) + public TcpConnector(string ipaddress, int port, int timeoutTime = 10000) : base(timeoutTime) { _host = ipaddress; _port = port; - TimeoutTime = timeoutTime; } - /// - /// 连接关键字 - /// + /// public override string ConnectionToken => _host; - /// - /// 超时时间 - /// - public int TimeoutTime + /// + protected override int TimeoutTime { get => _timeoutTime; @@ -88,14 +84,13 @@ namespace Modbus.Net } } - /// - /// 是否已经连接 - /// + /// public override bool IsConnected => _socketClient?.Client != null && _socketClient.Connected; - /// - /// 实现IDisposable接口 - /// + /// + protected override AsyncLock Lock { get; } = new AsyncLock(); + + /// public void Dispose() { Dispose(true); @@ -141,10 +136,7 @@ namespace Modbus.Net Dispose(false); } - /// - /// 连接 - /// - /// 是否连接成功 + /// public override async Task ConnectAsync() { if (_socketClient != null) @@ -184,10 +176,7 @@ namespace Modbus.Net } } - /// - /// 断开 - /// - /// 是否断开成功 + /// public override bool Disconnect() { if (_socketClient == null) @@ -211,36 +200,7 @@ namespace Modbus.Net } } - /// - /// 发送数据,需要返回 - /// - /// 发送的数据 - /// 是否发送成功 - public override async Task SendMsgAsync(byte[] message) - { - var task = SendMsgInner(message).WithCancellation(new CancellationTokenSource(10000).Token); - var ans = await task; - if (task.IsCanceled) - { - Controller.ForceRemoveWaitingMessage(ans); - return null; - } - return ans.ReceiveMessage; - } - - private async Task SendMsgInner(byte[] message) - { - var messageSendingdef = Controller.AddMessage(message); - messageSendingdef.SendMutex.WaitOne(); - await SendMsgWithoutConfirm(message); - messageSendingdef.ReceiveMutex.WaitOne(); - return messageSendingdef; - } - - /// - /// 发送信息,不进行返回确认 - /// - /// 发送的信息 + /// protected override async Task SendMsgWithoutConfirm(byte[] message) { var datagram = message; @@ -265,17 +225,13 @@ namespace Modbus.Net } } - /// - /// 启动获取线程 - /// + /// protected override void ReceiveMsgThreadStart() { _receiveThread = Task.Run(ReceiveMessage); } - /// - /// 停止获取线程 - /// + /// protected override void ReceiveMsgThreadStop() { _taskCancel = true;