using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Houdar.PLC.Driver.Simenss.Protocol.Iso;
using ByteBuffer = Houdar.Core.Communication.Transport.ByteBuffer;
namespace Houdar.PLC.Driver.Simenss.Communication
{
///
/// 采用同步通信机制
///
public class IsoSocket : IIsoSender
{
private Socket _socket;
public bool Connected
{
get
{
try
{
if (_socket == null)
return false;
return !((_socket.Poll(1000, SelectMode.SelectRead) && (_socket.Available == 0)) || !_socket.Connected);
}
catch { return false; }
}
}
private Action _messageAction;
public void RegisterMessage(Action messageAction)
{
if (messageAction == null) throw new ArgumentNullException("messageAction");
_messageAction = messageAction;
}
private void OnMessage(string methode, string message)
{
if (_messageAction != null)
_messageAction.Invoke(new MessageEvent(methode, message));
}
private static bool _isConnectionSuccessful = false;
private int _connecting;//连接中
public bool Connect(string ip, int port)
{
try
{
if (Interlocked.CompareExchange(ref _connecting, 1, 0) != 0)
{
OnMessage("Connect", "连接正在处理中");
return false;
}
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
IPEndPoint server = new IPEndPoint(IPAddress.Parse(ip), 102);
#region 添加的代码 20170801
timeoutObject = new ManualResetEvent(false);
_socket.BeginConnect(server, new AsyncCallback(CallBackMethod), _socket);
if (timeoutObject.WaitOne(1000, false))
{
if (_isConnectionSuccessful)
{
}
else
{
_socket.Close();
throw new Exception("连接超时");
}
}
#endregion;
#region 被注释的代码
//_socket.Connect(server);
#endregion;
return true;
}
catch (Exception ex)
{
OnMessage("Connect", "连接异常:{ex.Message}");
return false;
}
finally
{
Interlocked.CompareExchange(ref _connecting, 0, 1);
}
}
#region 添加的代码 20170801
private ManualResetEvent timeoutObject;//通知一个或多个正在等待的线程已发生事件
///
/// 连接过程中的异步回调
///
///
private void CallBackMethod(IAsyncResult asyncresult)
{
try
{
_isConnectionSuccessful = false;
_socket = asyncresult.AsyncState as Socket;
if (_socket != null)
{
_socket.EndConnect(asyncresult);
_isConnectionSuccessful = true;
}
}
catch (Exception ex)
{
_isConnectionSuccessful = false;
}
finally
{
timeoutObject.Set();//解除被阻塞的连接线程
}
}
#endregion;
private bool IsActive()
{
if (!Connected)
{
OnMessage("SendRecive", "未连接到PLC设备");
return false;
}
if (Interlocked.CompareExchange(ref _sending, 1, 0) != 0)
{
OnMessage("SendRecive", "正在处理中");
return false;
}
return true;
}
private int _sending;//发送中
public byte[] SendRecive(byte[] sendBytes, int length)
{
try
{
if (!IsActive()) return null;
var sendStr = BitConverter.ToString(sendBytes, 0, length);
//Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss ffff")}[Send]({length}):{sendStr}");
_socket.Send(sendBytes, length, SocketFlags.None);
byte[] bReceive = new byte[1024 * 4 * 8];
var resLength = _socket.Receive(bReceive, SocketFlags.None);
var recvStr = BitConverter.ToString(bReceive, 0, resLength);
//Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss ffff")}[Recv]({resLength}):{recvStr}");
var receiveBytes = new byte[resLength];
Array.Copy(bReceive, 0, receiveBytes, 0, resLength);
return receiveBytes;
}
catch (Exception ex)
{
OnMessage("Send", "发送异常:{ex.Message}");
return null;
}
finally
{
Interlocked.CompareExchange(ref _sending, 0, 1);
}
}
private TResponse GetResponse(byte[] resBytes, bool isContainHeader = true)
where TResponse : IBuildResponse, new()
{
ByteBuffer buffer= ByteBuffer.Allocate();
buffer.Push(resBytes);
if(isContainHeader)
{
IsoDataPdu pdu = new IsoDataPdu();
pdu.Build(buffer);
if (resBytes.Length != pdu.Length)
return default(TResponse);
}
TResponse response = new TResponse();
response.Build(buffer);
return response;
}
private ByteBuffer GetByteBuffer(TRequest request, bool isContainHeader=true)
where TRequest : IBuildRequest, new()
{
if(request==null) throw new ArgumentNullException("request");
request.Build();
var bufferData = request.GetBuffer();
ByteBuffer buffer = ByteBuffer.Allocate();
if(isContainHeader)
{
//构建ISO头部
IsoDataPdu pdu = new IsoDataPdu { Length = (ushort)bufferData.WriteIndex };
pdu.Build();
pdu.GetBuffer(buffer);
}
buffer.Push(bufferData.Buffer, bufferData.WriteIndex);
return buffer;
}
///
/// 不含ISO头的请求
///
///
///
///
///
public TResponse Send(TRequest request) where TRequest : IBuildRequest, new() where TResponse : IBuildResponse, new()
{
var buffer = GetByteBuffer(request, false);
var resByte = SendRecive(buffer.Buffer, buffer.WriteIndex);
if (resByte == null || resByte.Length == 0) return default(TResponse);
return GetResponse(resByte, false);
}
///
/// 包含ISO头的请求
///
///
///
///
///
public TResponse IsoSend(TRequest request) where TRequest : IBuildRequest, new() where TResponse : IBuildResponse, new()
{
try
{
var buffer = GetByteBuffer(request);
var resByte = SendRecive(buffer.Buffer, buffer.WriteIndex);
if (resByte == null) return default(TResponse);
return GetResponse(resByte);
}
catch (Exception ex)
{
return default(TResponse);
}
}
}
}