using PlcSiemens.O;
using PlcSiemens.Protocol.Iso;
using System.Net;
using System.Net.Sockets;
using ByteBuffer = PlcSiemens.O.ByteBuffer;
namespace PlcSiemens.Communication
{
///
/// 采用同步通信机制
///
public class IsoSocket : IIsoSender
{
private Socket _socket;
public bool Connected
{
get
{
try
{
if (_socket == null)
return false;
//return _socket.Connected;
//return _socket.Connected && (!(_socket.Available == 0) || !_socket.Poll(1000, SelectMode.SelectRead));
return !(!_socket.Connected || (_socket.Poll(1000, SelectMode.SelectRead) && (_socket.Available == 0)));
}
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 int _connecting;//连接中
private bool conneted = false;
public bool Connect(string ip, int port)
{
try
{
conneted = false;
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);
//_socket.Connect(server);
//return true;
timeoutObject.Reset();
_socket.BeginConnect(server, new AsyncCallback(Callback), _socket);
if (!timeoutObject.WaitOne(1000))
{
_socket.Close();
conneted = false;
}
return conneted;
}
catch (Exception ex)
{
OnMessage("Connect", "连接异常:{ex.Message}");
return false;
}
finally
{
Interlocked.CompareExchange(ref _connecting, 0, 1);
}
}
private ManualResetEvent timeoutObject = new ManualResetEvent(false);
private void Callback(IAsyncResult result)
{
try
{
var client = result.AsyncState as Socket;
if (client != null)
{
client.EndConnect(result);
conneted = true;
}
}
catch (Exception ex)
{
conneted = false;
}
finally
{
timeoutObject.Set();
}
}
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 * 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 (System.Net.Sockets.SocketException ex)
{
_socket.Close();
OnMessage("Send", "连接断开:" + ex.Message);
return null;
}
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()
{
var buffer = GetByteBuffer(request);
var resByte = SendRecive(buffer.Buffer, buffer.WriteIndex);
if (resByte == null)
return default(TResponse);
return GetResponse(resByte);
}
}
}