2017-12-26 Update 1 Controller and Connector Fix
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -44,19 +44,17 @@ namespace Modbus.Net
|
||||
}
|
||||
lock (WaitingMessages)
|
||||
{
|
||||
if (_currentSendingPos == null)
|
||||
{
|
||||
if (WaitingMessages.Count > 0)
|
||||
{
|
||||
_currentSendingPos = WaitingMessages.First();
|
||||
}
|
||||
}
|
||||
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 = WaitingMessages.Count <= 1
|
||||
? null
|
||||
: WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Modbus.Net
|
||||
/// <summary>
|
||||
/// 基础的协议连接接口
|
||||
/// </summary>
|
||||
public interface IConnector<TParamIn, TParamOut>
|
||||
public interface IConnector<in TParamIn, TParamOut>
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识Connector的连接关键字
|
||||
|
||||
@@ -56,14 +56,20 @@ namespace Modbus.Net
|
||||
if (WaitingMessages.Count > 0)
|
||||
{
|
||||
_currentSendingPos = WaitingMessages.First();
|
||||
_currentSendingPos.SendMutex.Set();
|
||||
}
|
||||
}
|
||||
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 = WaitingMessages.Count <= 1
|
||||
? null
|
||||
: WaitingMessages[WaitingMessages.IndexOf(_currentSendingPos) + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user