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 namespace Modbus.Net
{ {
/// <summary> /// <inheritdoc />
/// 基础的协议连接类
/// </summary>
public abstract class BaseConnector : BaseConnector<byte[], byte[]> 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> /// <summary>
@@ -32,33 +122,19 @@ namespace Modbus.Net
/// </summary> /// </summary>
protected virtual IController Controller { get; set; } protected virtual IController Controller { get; set; }
/// <summary> /// <inheritdoc />
/// 标识Connector的连接关键字
/// </summary>
public abstract string ConnectionToken { get; } public abstract string ConnectionToken { get; }
/// <summary> /// <inheritdoc />
/// 是否处于连接状态
/// </summary>
public abstract bool IsConnected { get; } public abstract bool IsConnected { get; }
/// <summary> /// <inheritdoc />
/// 连接PLC异步
/// </summary>
/// <returns>是否连接成功</returns>
public abstract Task<bool> ConnectAsync(); public abstract Task<bool> ConnectAsync();
/// <summary> /// <inheritdoc />
/// 断开PLC
/// </summary>
/// <returns>是否断开成功</returns>
public abstract bool Disconnect(); public abstract bool Disconnect();
/// <summary> /// <inheritdoc />
/// 带返回发送数据
/// </summary>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract Task<TParamOut> SendMsgAsync(TParamIn message); public abstract Task<TParamOut> SendMsgAsync(TParamIn message);
/// <summary> /// <summary>

View File

@@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO.Ports; using System.IO.Ports;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Nito.AsyncEx; using Nito.AsyncEx;
@@ -57,17 +55,29 @@ namespace Modbus.Net
/// </summary> /// </summary>
private readonly StopBits _stopBits; private readonly StopBits _stopBits;
/// <inheritdoc />
protected override int TimeoutTime { get; set; }
/// <summary> /// <summary>
/// 超时时间 /// 错误次数
/// </summary> /// </summary>
private readonly int _timeoutTime;
private int _errorCount; private int _errorCount;
/// <summary>
/// 获取次数
/// </summary>
private int _receiveCount; private int _receiveCount;
/// <summary>
/// 发送次数
/// </summary>
private int _sendCount; private int _sendCount;
/// <summary>
/// 获取线程
/// </summary>
private Task _receiveThread; private Task _receiveThread;
/// <summary>
/// 获取线程关闭
/// </summary>
private bool _taskCancel = false; private bool _taskCancel = false;
/// <summary> /// <summary>
@@ -84,12 +94,11 @@ namespace Modbus.Net
/// <param name="stopBits">停止位</param> /// <param name="stopBits">停止位</param>
/// <param name="dataBits">数据位</param> /// <param name="dataBits">数据位</param>
/// <param name="timeoutTime">超时时间</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]; _com = com.Split(':')[0];
//读超时
_timeoutTime = timeoutTime;
//波特率 //波特率
_baudRate = baudRate; _baudRate = baudRate;
//奇偶校验 //奇偶校验
@@ -108,6 +117,9 @@ namespace Modbus.Net
private static Dictionary<string, SerialPortLock> Connectors { get; } = new Dictionary<string, SerialPortLock>() private static Dictionary<string, SerialPortLock> Connectors { get; } = new Dictionary<string, SerialPortLock>()
; ;
/// <summary>
/// 连接中的连接器
/// </summary>
private static Dictionary<string, IController> Controllers { get; } = new Dictionary<string, IController>() 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>
/// 连接中的连接器 /// 连接中的连接器
/// </summary> /// </summary>
@@ -140,6 +155,9 @@ namespace Modbus.Net
/// </summary> /// </summary>
public override string ConnectionToken => _slave + ":" + _com; public override string ConnectionToken => _slave + ":" + _com;
/// <summary>
/// 获取当前连接器使用的串口
/// </summary>
private SerialPortLock SerialPort private SerialPortLock SerialPort
{ {
get get
@@ -150,9 +168,7 @@ namespace Modbus.Net
} }
} }
/// <summary> /// <inheritdoc />
/// 实现IDisposable接口
/// </summary>
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@@ -292,8 +308,6 @@ namespace Modbus.Net
Log.Verbose("Com client {ConnectionToken} error count: {ErrorCount}", ConnectionToken, _errorCount); Log.Verbose("Com client {ConnectionToken} error count: {ErrorCount}", ConnectionToken, _errorCount);
} }
#region
/// <inheritdoc /> /// <inheritdoc />
public override bool IsConnected public override bool IsConnected
{ {
@@ -324,7 +338,7 @@ namespace Modbus.Net
Parity = _parity, Parity = _parity,
StopBits = _stopBits, StopBits = _stopBits,
DataBits = _dataBits, DataBits = _dataBits,
ReadTimeout = _timeoutTime ReadTimeout = TimeoutTime
}); });
} }
if (!Linkers.ContainsKey(_slave)) if (!Linkers.ContainsKey(_slave))
@@ -379,16 +393,18 @@ namespace Modbus.Net
return false; return false;
} }
#region
/// <summary> /// <summary>
/// 带返回发送数据 /// 带返回发送数据
/// </summary> /// </summary>
/// <param name="sendStr">需要发送的数据</param> /// <param name="sendStr">需要发送的数据</param>
/// <returns>是否发送成功</returns> /// <returns>是否发送成功</returns>
public string SendMsg(string sendStr) public async Task<string> SendMsgAsync(string sendStr)
{ {
var myByte = sendStr.StringToByte_2(); var myByte = sendStr.StringToByte_2();
var returnBytes = SendMsg(myByte); var returnBytes = await SendMsgAsync(myByte);
return returnBytes.ByteToString(); 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 /> /// <inheritdoc />
public override async Task<byte[]> SendMsgAsync(byte[] message) public override async Task<byte[]> SendMsgAsync(byte[] message)
{ {
CheckOpen(); CheckOpen();
var task = SendMsgInner(message).WithCancellation(new CancellationTokenSource(100000).Token); return await base.SendMsgAsync(message);
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;
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -44,19 +44,17 @@ namespace Modbus.Net
} }
lock (WaitingMessages) lock (WaitingMessages)
{ {
if (_currentSendingPos == null)
{
if (WaitingMessages.Count > 0)
{
_currentSendingPos = WaitingMessages.First();
}
}
if (_currentSendingPos != null) if (_currentSendingPos != null)
{ {
if (WaitingMessages.Count <= 0)
{
_currentSendingPos = null;
}
if (WaitingMessages.Count > WaitingMessages.IndexOf(_currentSendingPos) + 1)
{
_currentSendingPos = WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1];
_currentSendingPos.SendMutex.Set(); _currentSendingPos.SendMutex.Set();
_currentSendingPos = WaitingMessages.Count <= 1 }
? null
: WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1];
} }
} }
} }

View File

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

View File

@@ -56,14 +56,20 @@ namespace Modbus.Net
if (WaitingMessages.Count > 0) if (WaitingMessages.Count > 0)
{ {
_currentSendingPos = WaitingMessages.First(); _currentSendingPos = WaitingMessages.First();
_currentSendingPos.SendMutex.Set();
} }
} }
if (_currentSendingPos != null) if (_currentSendingPos != null)
{ {
if (WaitingMessages.Count <= 0)
{
_currentSendingPos = null;
}
if (WaitingMessages.Count > WaitingMessages.IndexOf(_currentSendingPos) + 1)
{
_currentSendingPos = WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1];
_currentSendingPos.SendMutex.Set(); _currentSendingPos.SendMutex.Set();
_currentSendingPos = WaitingMessages.Count <= 1 }
? null
: WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1];
} }
} }
} }

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Nito.AsyncEx;
using Serilog; using Serilog;
namespace Modbus.Net namespace Modbus.Net
@@ -61,22 +62,17 @@ namespace Modbus.Net
/// <param name="ipaddress">Ip地址</param> /// <param name="ipaddress">Ip地址</param>
/// <param name="port">端口</param> /// <param name="port">端口</param>
/// <param name="timeoutTime">超时时间</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; _host = ipaddress;
_port = port; _port = port;
TimeoutTime = timeoutTime;
} }
/// <summary> /// <inheritdoc />
/// 连接关键字
/// </summary>
public override string ConnectionToken => _host; public override string ConnectionToken => _host;
/// <summary> /// <inheritdoc />
/// 超时时间 protected override int TimeoutTime
/// </summary>
public int TimeoutTime
{ {
get => get =>
_timeoutTime; _timeoutTime;
@@ -88,14 +84,13 @@ namespace Modbus.Net
} }
} }
/// <summary> /// <inheritdoc />
/// 是否已经连接
/// </summary>
public override bool IsConnected => _socketClient?.Client != null && _socketClient.Connected; public override bool IsConnected => _socketClient?.Client != null && _socketClient.Connected;
/// <summary> /// <inheritdoc />
/// 实现IDisposable接口 protected override AsyncLock Lock { get; } = new AsyncLock();
/// </summary>
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@@ -141,10 +136,7 @@ namespace Modbus.Net
Dispose(false); Dispose(false);
} }
/// <summary> /// <inheritdoc />
/// 连接
/// </summary>
/// <returns>是否连接成功</returns>
public override async Task<bool> ConnectAsync() public override async Task<bool> ConnectAsync()
{ {
if (_socketClient != null) if (_socketClient != null)
@@ -184,10 +176,7 @@ namespace Modbus.Net
} }
} }
/// <summary> /// <inheritdoc />
/// 断开
/// </summary>
/// <returns>是否断开成功</returns>
public override bool Disconnect() public override bool Disconnect()
{ {
if (_socketClient == null) if (_socketClient == null)
@@ -211,36 +200,7 @@ namespace Modbus.Net
} }
} }
/// <summary> /// <inheritdoc />
/// 发送数据,需要返回
/// </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>
protected override async Task SendMsgWithoutConfirm(byte[] message) protected override async Task SendMsgWithoutConfirm(byte[] message)
{ {
var datagram = message; var datagram = message;
@@ -265,17 +225,13 @@ namespace Modbus.Net
} }
} }
/// <summary> /// <inheritdoc />
/// 启动获取线程
/// </summary>
protected override void ReceiveMsgThreadStart() protected override void ReceiveMsgThreadStart()
{ {
_receiveThread = Task.Run(ReceiveMessage); _receiveThread = Task.Run(ReceiveMessage);
} }
/// <summary> /// <inheritdoc />
/// 停止获取线程
/// </summary>
protected override void ReceiveMsgThreadStop() protected override void ReceiveMsgThreadStop()
{ {
_taskCancel = true; _taskCancel = true;