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