2015-04-08 update 1 change some code in TCP Connector to implement async method

This commit is contained in:
parallelbgls@outlook.com
2015-04-08 15:41:20 +08:00
parent 3f4fe27a5e
commit a9bcd06b2b
12 changed files with 158 additions and 122 deletions

View File

@@ -15,6 +15,11 @@ namespace ModBus.Net
/// <returns></returns> /// <returns></returns>
public abstract bool Connect(); public abstract bool Connect();
/// <summary> /// <summary>
/// 连接PLC异步
/// </summary>
/// /// <returns></returns>
public abstract Task<bool> ConnectAsync();
/// <summary>
/// 断开PLC /// 断开PLC
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
@@ -26,10 +31,22 @@ namespace ModBus.Net
/// <returns></returns> /// <returns></returns>
public abstract bool SendMsgWithoutReturn(byte[] message); public abstract bool SendMsgWithoutReturn(byte[] message);
/// <summary> /// <summary>
/// 无返回发送数据,异步
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public abstract Task<bool> SendMsgWithoutReturnAsync(byte[] message);
/// <summary>
/// 带返回发送数据 /// 带返回发送数据
/// </summary> /// </summary>
/// <param name="message"></param> /// <param name="message"></param>
/// <returns></returns> /// <returns></returns>
public abstract byte[] SendMsg(byte[] message); public abstract byte[] SendMsg(byte[] message);
/// <summary>
/// 带返回发送数据,异步
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public abstract Task<byte[]> SendMsgAsync(byte[] message);
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
namespace ModBus.Net namespace ModBus.Net
{ {

View File

@@ -52,6 +52,11 @@ namespace ModBus.Net
return false; return false;
} }
public override Task<bool> ConnectAsync()
{
return Task.FromResult(Connect());
}
public override bool Disconnect() public override bool Disconnect()
{ {
if (serialPort1 != null) if (serialPort1 != null)
@@ -77,6 +82,11 @@ namespace ModBus.Net
} }
public override Task<bool> SendMsgWithoutReturnAsync(byte[] message)
{
return Task.FromResult(SendMsgWithoutReturn(message));
}
public override byte[] SendMsg(byte[] sendbytes) public override byte[] SendMsg(byte[] sendbytes)
{ {
try try
@@ -95,6 +105,11 @@ namespace ModBus.Net
} }
} }
public override Task<byte[]> SendMsgAsync(byte[] message)
{
return Task.FromResult(SendMsg(message));
}
public override bool SendMsgWithoutReturn(byte[] sendbytes) public override bool SendMsgWithoutReturn(byte[] sendbytes)
{ {
try try

View File

@@ -30,6 +30,12 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>key.pfx</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -42,6 +48,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AddressTranslator.cs" /> <Compile Include="AddressTranslator.cs" />
<Compile Include="AsyncHelper.cs" />
<Compile Include="BaseProtocal.cs" /> <Compile Include="BaseProtocal.cs" />
<Compile Include="BaseUtility.cs" /> <Compile Include="BaseUtility.cs" />
<Compile Include="ComConnector.cs" /> <Compile Include="ComConnector.cs" />
@@ -82,6 +89,9 @@
<LastGenOutput>ConfigurationManager.Designer.cs</LastGenOutput> <LastGenOutput>ConfigurationManager.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="key.pfx" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
/// <summary> /// <summary>

View File

@@ -1,4 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
namespace ModBus.Net namespace ModBus.Net
{ {

View File

@@ -34,6 +34,16 @@ namespace ModBus.Net
_maxPdu = 0x03c0; _maxPdu = 0x03c0;
break; break;
} }
case "300":
case "400":
{
_taspSrc = 0x4b54;
_tsapDst = 0x0302;
_maxCalling = 0x0001;
_maxCalled = 0x0001;
_maxPdu = 0x00f0;
break;
}
} }
_connectionString = splitStrings[0]; _connectionString = splitStrings[0];
} }

View File

@@ -1,6 +1,9 @@
using System; using System;
using System.IO;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
namespace ModBus.Net namespace ModBus.Net
{ {
@@ -23,68 +26,73 @@ namespace ModBus.Net
/// </summary> /// </summary>
public class TcpConnector : BaseConnector, IDisposable public class TcpConnector : BaseConnector, IDisposable
{ {
public delegate void ErrorShutdownEventHandler(object sender, EventArgs e);
public delegate void ReceiveMessageHandler(object sender, SocketMessageEventArgs e); private readonly string _host;
private readonly bool b_AsyncReceive = true; private int _sendCount;
private readonly string host; private int _receiveCount;
private int _errorCount;
private NetworkStream _stream;
// 2MB 的接收缓冲区,目的是一次接收完服务器发回的消息 // 2MB 的接收缓冲区,目的是一次接收完服务器发回的消息
private readonly byte[] m_receiveBuffer = new byte[1024]; private readonly byte[] _receiveBuffer = new byte[1024];
private readonly int port; private readonly int _port;
public int m_errorCount = 0; private TcpClient _socketClient;
public int m_receiveCount = 0;
public int m_sendCount = 0;
private TcpClient m_socketClient;
public TcpConnector(string ipaddress, int port, bool isAsync) public int TimeoutTime { get; set; }
public TcpConnector(string ipaddress, int port, int timeoutTime)
{ {
host = ipaddress; _host = ipaddress;
this.port = port; _port = port;
b_AsyncReceive = isAsync; //TimeoutTime = timeoutTime;
} }
public override bool IsConnected public override bool IsConnected
{ {
get { return m_socketClient != null && m_socketClient.Connected; } get { return _socketClient != null && _socketClient.Connected; }
} }
public void Dispose() public void Dispose()
{ {
if (m_socketClient != null) if (_socketClient != null)
{ {
CloseClientSocket(); CloseClientSocket();
m_socketClient.Client.Dispose(); _socketClient.Client.Dispose();
}
}
public event ReceiveMessageHandler MessageReceive;
public event ErrorShutdownEventHandler SocketErrorShutdown;
private void ReceiveMessage(byte[] message)
{
if (MessageReceive != null)
{
MessageReceive(this, new SocketMessageEventArgs(message));
} }
} }
public override bool Connect() public override bool Connect()
{ {
if (m_socketClient != null) return AsyncHelper.RunSync(ConnectAsync);
}
public override async Task<bool> ConnectAsync()
{
if (_socketClient != null)
{ {
Disconnect(); Disconnect();
} }
lock (this)
{
try try
{ {
m_socketClient = new TcpClient(host, port); _socketClient = new TcpClient
m_socketClient.ReceiveTimeout = 10*1000;
if (m_socketClient.Connected)
{ {
SendTimeout = TimeoutTime,
ReceiveTimeout = TimeoutTime
};
try
{
await _socketClient.ConnectAsync(_host, _port);
}
catch (Exception e)
{
AddInfo("client connected exception: " + e.Message);
}
if (_socketClient.Connected)
{
_stream = _socketClient.GetStream();
AddInfo("client connected."); AddInfo("client connected.");
return true; return true;
} }
@@ -97,20 +105,17 @@ namespace ModBus.Net
return false; return false;
} }
} }
}
public override bool Disconnect() public override bool Disconnect()
{ {
lock (this) if (_socketClient == null)
{
if (m_socketClient == null)
{ {
return true; return true;
} }
try try
{ {
m_socketClient.Close(); _socketClient.Close();
AddInfo("client disconnected successfully."); AddInfo("client disconnected successfully.");
return true; return true;
} }
@@ -121,8 +126,7 @@ namespace ModBus.Net
} }
finally finally
{ {
m_socketClient = null; _socketClient = null;
}
} }
} }
@@ -131,18 +135,28 @@ namespace ModBus.Net
Console.WriteLine(message); Console.WriteLine(message);
} }
public override bool SendMsgWithoutReturn(byte[] message)
{
return AsyncHelper.RunSync(() => SendMsgWithoutReturnAsync(message));
}
/// <summary> /// <summary>
/// 发送数据,不需要返回任何值 /// 发送数据,不需要返回任何值
/// </summary> /// </summary>
/// <param name="message">发送的信息</param> /// <param name="message">发送的信息</param>
/// <returns>是否发送成功</returns> /// <returns>是否发送成功</returns>
public override bool SendMsgWithoutReturn(byte[] message) public override async Task<bool> SendMsgWithoutReturnAsync(byte[] message)
{ {
byte[] datagram = message; byte[] datagram = message;
try try
{ {
m_socketClient.Client.Send(datagram); if (!IsConnected)
{
await ConnectAsync();
}
await _stream.WriteAsync(datagram, 0, datagram.Length);
RefreshSendCount(); RefreshSendCount();
//this.AddInfo("send text len = " + datagramText.Length.ToString()); //this.AddInfo("send text len = " + datagramText.Length.ToString());
@@ -156,12 +170,17 @@ namespace ModBus.Net
} }
} }
public override byte[] SendMsg(byte[] message)
{
return AsyncHelper.RunSync(() => SendMsgAsync(message));
}
/// <summary> /// <summary>
/// 发送数据,需要返回 /// 发送数据,需要返回
/// </summary> /// </summary>
/// <param name="message">发送的数据</param> /// <param name="message">发送的数据</param>
/// <returns>是否发送成功</returns> /// <returns>是否发送成功</returns>
public override byte[] SendMsg(byte[] message) public override async Task<byte[]> SendMsgAsync(byte[] message)
{ {
byte[] datagram = message; byte[] datagram = message;
@@ -169,14 +188,16 @@ namespace ModBus.Net
{ {
if (!IsConnected) if (!IsConnected)
{ {
Connect(); await ConnectAsync();
} }
m_socketClient.Client.Send(datagram);
var stream = _socketClient.GetStream();
await stream.WriteAsync(datagram, 0, datagram.Length);
RefreshSendCount(); RefreshSendCount();
//this.AddInfo("send text len = " + datagramText.Length.ToString()); //this.AddInfo("send text len = " + datagramText.Length.ToString());
return Receive(); return await ReceiveAsync(stream);
} }
catch (Exception err) catch (Exception err)
{ {
@@ -186,19 +207,12 @@ namespace ModBus.Net
} }
} }
public byte[] Receive() protected async Task<byte[]> ReceiveAsync(NetworkStream stream)
{ {
try try
{ {
int len = await stream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length);
// 异步接收回答 // 异步接收回答
if (b_AsyncReceive)
{
m_socketClient.Client.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None,
EndReceiveDatagram, this);
return null;
}
// 同步接收回答
int len = m_socketClient.Client.Receive(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None);
if (len > 0) if (len > 0)
{ {
return CheckReplyDatagram(len); return CheckReplyDatagram(len);
@@ -220,10 +234,9 @@ namespace ModBus.Net
private byte[] CheckReplyDatagram(int len) private byte[] CheckReplyDatagram(int len)
{ {
var replyMessage = new byte[len]; var replyMessage = new byte[len];
Array.Copy(m_receiveBuffer, replyMessage, len); Array.Copy(_receiveBuffer, replyMessage, len);
//this.AddInfo("reply: " + replyMesage); //this.AddInfo("reply: " + replyMesage);
ReceiveMessage(replyMessage);
RefreshReceiveCount(); RefreshReceiveCount();
if (len <= 0) if (len <= 0)
@@ -236,63 +249,30 @@ namespace ModBus.Net
private void RefreshSendCount() private void RefreshSendCount()
{ {
m_sendCount++; _sendCount++;
} }
private void RefreshReceiveCount() private void RefreshReceiveCount()
{ {
m_receiveCount++; _receiveCount++;
} }
private void RefreshErrorCount() private void RefreshErrorCount()
{ {
m_errorCount++; _errorCount++;
} }
private void CloseClientSocket() private void CloseClientSocket()
{ {
try try
{ {
m_socketClient.Client.Shutdown(SocketShutdown.Both); _stream.Close();
m_socketClient.Client.Close(); _socketClient.Client.Shutdown(SocketShutdown.Both);
if (!IsConnected) _socketClient.Client.Close();
{
if (SocketErrorShutdown != null)
{
Thread.Sleep(1000);
SocketErrorShutdown(this, new EventArgs());
AddInfo("socket error disconnected!");
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
//this.AddInfo("client close exception: " + ex.Message); AddInfo("client close exception: " + ex.Message);
}
}
/// <summary>
/// 异步接收消息返回函数
/// </summary>
/// <param name="iar">异步参数</param>
private void EndReceiveDatagram(IAsyncResult iar)
{
try
{
int readBytesLength = m_socketClient.Client.EndReceive(iar);
if (readBytesLength == 0)
{
CloseClientSocket();
}
else // 正常数据包
{
CheckReplyDatagram(readBytesLength);
}
}
catch (Exception err)
{
AddInfo("receive exception: " + err.Message);
CloseClientSocket();
} }
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
namespace ModBus.Net namespace ModBus.Net
{ {
@@ -17,7 +18,7 @@ namespace ModBus.Net
protected TcpProtocalLinker(string ip, int port) protected TcpProtocalLinker(string ip, int port)
{ {
_baseConnector = new TcpConnector(ip, port, false); _baseConnector = new TcpConnector(ip, port, 10000);
} }
} }
} }

View File

@@ -25,7 +25,7 @@ namespace ModBus.Net
{"System.Double", 8} {"System.Double", 8}
}; };
protected static bool _littleEndian = false; protected static bool _littleEndian = true;
protected ValueHelper() protected ValueHelper()
{ {
@@ -41,7 +41,7 @@ namespace ModBus.Net
{ {
_littleEndian = value; _littleEndian = value;
//这里需要重点说明,因为.net默认是小端构造法所以目标协议是大端的话反而需要调用小端构造协议把小端反转为大端。 //这里需要重点说明,因为.net默认是小端构造法所以目标协议是大端的话反而需要调用小端构造协议把小端反转为大端。
_Instance = LittleEndian ? new ValueHelper() : new LittleEndianValueHelper(); _Instance = LittleEndian ? new LittleEndianValueHelper() : new ValueHelper();
} }
} }
@@ -58,7 +58,7 @@ namespace ModBus.Net
{ {
if (_Instance == null) if (_Instance == null)
{ {
_Instance = LittleEndian ? new ValueHelper() : new LittleEndianValueHelper(); _Instance = LittleEndian ? new LittleEndianValueHelper() : new ValueHelper();
} }
return _Instance; return _Instance;
} }
@@ -285,7 +285,7 @@ namespace ModBus.Net
byte temp = data[pos]; byte temp = data[pos];
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
t[7 - i] = temp%2 > 0; t[i] = temp % 2 > 0;
temp /= 2; temp /= 2;
} }
pos += 1; pos += 1;
@@ -709,7 +709,7 @@ namespace ModBus.Net
byte temp = data[pos]; byte temp = data[pos];
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
t[i] = temp%2 > 0; t[7 - i] = temp % 2 > 0;
temp /= 2; temp /= 2;
} }
pos += 1; pos += 1;

Binary file not shown.