2017-12-26 Update 1 Controller and Connector Fix

This commit is contained in:
parallelbgls
2017-12-26 15:08:02 +08:00
parent f5a0a6533c
commit fcb463348c
6 changed files with 168 additions and 145 deletions

View File

@@ -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
{
/// <summary>
/// 基础的协议连接类
/// </summary>
/// <inheritdoc />
public abstract class BaseConnector : BaseConnector<byte[], byte[]>
{
/// <summary>
/// 发送锁
/// </summary>
protected abstract AsyncLock Lock { get; }
/// <summary>
/// 是否为全双工
/// </summary>
public bool IsFullDuplex { get; }
/// <summary>
/// 发送超时时间
/// </summary>
protected abstract int TimeoutTime { get; set; }
/// <summary>
/// 构造器
/// </summary>
/// <param name="timeoutTime">发送超时时间</param>
/// <param name="isFullDuplex">是否为全双工</param>
protected BaseConnector(int timeoutTime = 10000, bool isFullDuplex = true)
{
IsFullDuplex = isFullDuplex;
TimeoutTime = timeoutTime;
}
/// <inheritdoc />
public override async Task<byte[]> SendMsgAsync(byte[] message)
{
var ans = await SendMsgCtrl(message);
return ans?.ReceiveMessage;
}
/// <summary>
/// 发送主控
/// </summary>
/// <param name="message">发送的信息</param>
/// <returns>等待信息的定义</returns>
protected async Task<MessageWaitingDef> SendMsgCtrl(byte[] message)
{
MessageWaitingDef ans;
if (!IsFullDuplex)
{
using (await Lock.LockAsync())
{
ans = await SendMsgInner(message);
}
}
else
{
ans = await SendMsgInner(message);
}
return ans;
}
/// <summary>
/// 发送内部
/// </summary>
/// <param name="message">发送的信息</param>
/// <returns>发送信息的定义</returns>
protected async Task<MessageWaitingDef> 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;
}
}
}
/// <summary>
@@ -32,33 +122,19 @@ namespace Modbus.Net
/// </summary>
protected virtual IController Controller { get; set; }
/// <summary>
/// 标识Connector的连接关键字
/// </summary>
/// <inheritdoc />
public abstract string ConnectionToken { get; }
/// <summary>
/// 是否处于连接状态
/// </summary>
/// <inheritdoc />
public abstract bool IsConnected { get; }
/// <summary>
/// 连接PLC异步
/// </summary>
/// <returns>是否连接成功</returns>
/// <inheritdoc />
public abstract Task<bool> ConnectAsync();
/// <summary>
/// 断开PLC
/// </summary>
/// <returns>是否断开成功</returns>
/// <inheritdoc />
public abstract bool Disconnect();
/// <summary>
/// 带返回发送数据
/// </summary>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
/// <inheritdoc />
public abstract Task<TParamOut> SendMsgAsync(TParamIn message);
/// <summary>

View File

@@ -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
/// </summary>
private readonly StopBits _stopBits;
/// <inheritdoc />
protected override int TimeoutTime { get; set; }
/// <summary>
/// 超时时间
/// 错误次数
/// </summary>
private readonly int _timeoutTime;
private int _errorCount;
/// <summary>
/// 获取次数
/// </summary>
private int _receiveCount;
/// <summary>
/// 发送次数
/// </summary>
private int _sendCount;
/// <summary>
/// 获取线程
/// </summary>
private Task _receiveThread;
/// <summary>
/// 获取线程关闭
/// </summary>
private bool _taskCancel = false;
/// <summary>
@@ -84,12 +94,11 @@ namespace Modbus.Net
/// <param name="stopBits">停止位</param>
/// <param name="dataBits">数据位</param>
/// <param name="timeoutTime">超时时间</param>
public ComConnector(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits, int timeoutTime)
/// <param name="isFullDuplex">是否为全双工</param>
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<string, SerialPortLock> Connectors { get; } = new Dictionary<string, SerialPortLock>()
;
/// <summary>
/// 连接中的连接器
/// </summary>
private static Dictionary<string, IController> Controllers { get; } = new Dictionary<string, IController>()
;
@@ -130,6 +142,9 @@ namespace Modbus.Net
}
}
/// <inheritdoc />
protected override AsyncLock Lock => SerialPort.Lock;
/// <summary>
/// 连接中的连接器
/// </summary>
@@ -140,6 +155,9 @@ namespace Modbus.Net
/// </summary>
public override string ConnectionToken => _slave + ":" + _com;
/// <summary>
/// 获取当前连接器使用的串口
/// </summary>
private SerialPortLock SerialPort
{
get
@@ -150,9 +168,7 @@ namespace Modbus.Net
}
}
/// <summary>
/// 实现IDisposable接口
/// </summary>
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
@@ -292,8 +308,6 @@ namespace Modbus.Net
Log.Verbose("Com client {ConnectionToken} error count: {ErrorCount}", ConnectionToken, _errorCount);
}
#region
/// <inheritdoc />
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
/// <summary>
/// 带返回发送数据
/// </summary>
/// <param name="sendStr">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public string SendMsg(string sendStr)
public async Task<string> 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
}
}
/// <summary>
/// 发送数据,需要返回
/// </summary>
/// <param name="message">发送的数据</param>
/// <returns>是否发送成功</returns>
protected byte[] SendMsg(byte[] message)
{
return AsyncHelper.RunSync(() => SendMsgAsync(message));
}
/// <inheritdoc />
public override async Task<byte[]> 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<MessageWaitingDef> 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);
}
/// <inheritdoc />

View File

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

View File

@@ -5,7 +5,7 @@ namespace Modbus.Net
/// <summary>
/// 基础的协议连接接口
/// </summary>
public interface IConnector<TParamIn, TParamOut>
public interface IConnector<in TParamIn, TParamOut>
{
/// <summary>
/// 标识Connector的连接关键字

View File

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

View File

@@ -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
/// <param name="ipaddress">Ip地址</param>
/// <param name="port">端口</param>
/// <param name="timeoutTime">超时时间</param>
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;
}
/// <summary>
/// 连接关键字
/// </summary>
/// <inheritdoc />
public override string ConnectionToken => _host;
/// <summary>
/// 超时时间
/// </summary>
public int TimeoutTime
/// <inheritdoc />
protected override int TimeoutTime
{
get =>
_timeoutTime;
@@ -88,14 +84,13 @@ namespace Modbus.Net
}
}
/// <summary>
/// 是否已经连接
/// </summary>
/// <inheritdoc />
public override bool IsConnected => _socketClient?.Client != null && _socketClient.Connected;
/// <summary>
/// 实现IDisposable接口
/// </summary>
/// <inheritdoc />
protected override AsyncLock Lock { get; } = new AsyncLock();
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
@@ -141,10 +136,7 @@ namespace Modbus.Net
Dispose(false);
}
/// <summary>
/// 连接
/// </summary>
/// <returns>是否连接成功</returns>
/// <inheritdoc />
public override async Task<bool> ConnectAsync()
{
if (_socketClient != null)
@@ -184,10 +176,7 @@ namespace Modbus.Net
}
}
/// <summary>
/// 断开
/// </summary>
/// <returns>是否断开成功</returns>
/// <inheritdoc />
public override bool Disconnect()
{
if (_socketClient == null)
@@ -211,36 +200,7 @@ namespace Modbus.Net
}
}
/// <summary>
/// 发送数据,需要返回
/// </summary>
/// <param name="message">发送的数据</param>
/// <returns>是否发送成功</returns>
public override async Task<byte[]> 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<MessageWaitingDef> SendMsgInner(byte[] message)
{
var messageSendingdef = Controller.AddMessage(message);
messageSendingdef.SendMutex.WaitOne();
await SendMsgWithoutConfirm(message);
messageSendingdef.ReceiveMutex.WaitOne();
return messageSendingdef;
}
/// <summary>
/// 发送信息,不进行返回确认
/// </summary>
/// <param name="message">发送的信息</param>
/// <inheritdoc />
protected override async Task SendMsgWithoutConfirm(byte[] message)
{
var datagram = message;
@@ -265,17 +225,13 @@ namespace Modbus.Net
}
}
/// <summary>
/// 启动获取线程
/// </summary>
/// <inheritdoc />
protected override void ReceiveMsgThreadStart()
{
_receiveThread = Task.Run(ReceiveMessage);
}
/// <summary>
/// 停止获取线程
/// </summary>
/// <inheritdoc />
protected override void ReceiveMsgThreadStop()
{
_taskCancel = true;