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); } } } }