using System; using System.Net.Sockets; using Curtain.Net.Sockets.PLC.ThreadLock; namespace Curtain.Net.Sockets.PLC { /// /// Socket 通信基类 /// public abstract class PLCSocket : IDisposable { #region 变量 #endregion #region 属性 /// /// 销毁状态 /// public bool IsDispose { get; protected set; } /// /// 通信用Socket /// public Socket Socket { get; protected set; } /// /// 线程锁 /// public IThreadLock ThreadLock { get; protected set; } = new ReaderWriterThreadLock(); #endregion #region 构造 /// /// Socket 通信基类 /// public PLCSocket() { } /// /// Socket 通信基类 /// /// Socket public PLCSocket(Socket socket) { this.Socket = socket; } #endregion #region 连接&关闭 /// /// 创建Socket /// /// /// /// public virtual void CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { if (Socket != null) { try { //if (Socket.Connected) //{ // Socket.Close(); //} Socket.Dispose(); } catch { } } if (IsDispose) { IsDispose = false; } if (ThreadLock == null) { ThreadLock = new ReaderWriterThreadLock(); } Socket = new Socket(addressFamily, socketType, protocolType); } /// /// 创建Socket /// public virtual void CreateSocket() { CreateSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } /// /// 连接Socket /// /// /// public virtual void Connect(string host, int port) { if (this.Socket == null) { this.CreateSocket(); } //else //{ // // 刷新 Connected 状态(服务端关闭连接时,客户端 Connected=true)。 // try // { // bool b = Socket.EnableBroadcast; // } // catch // { // } //} if (!this.Socket.Connected) { try { this.Socket.Connect(host, port); this.OnSocketConnect(); } //catch (InvalidOperationException ex) catch //(Exception ex) { this.Close(); this.CreateSocket(); this.Socket.Connect(host, port); this.OnSocketConnect(); } } } /// /// Socket连接后PLC初始化 /// public virtual void OnSocketConnect() { } /// /// 断开连接 /// public virtual void Disconnect() { if (this.Socket == null) { return; } if (this.Socket.Connected) { try { this.Socket.Disconnect(true); } catch //(Exception ex) { this.Close(); this.Socket = null; } } } /// /// 关闭Socket /// /// public virtual bool Close() { if (Socket == null) { return true; } try { Socket.Close(); Socket = null; } catch //(Exception ex) { return false; } return true; } /// /// 销毁 /// public virtual void Dispose() { try { Socket?.Dispose(); Socket = null; ThreadLock.Dispose(); ThreadLock = null; } catch { } finally { IsDispose = true; } } #endregion #region Send /// /// 发送 /// /// /// internal protected virtual PLCResult Send(byte[] data) { PLCResult plcResult = new PLCResult(); if (data == null || data.Length == 0) { plcResult.Successed = false; plcResult.Message = "no command"; return plcResult; } if (Socket == null) { plcResult.Successed = false; plcResult.Message = "no socket"; return plcResult; } if (!Socket.Connected) { plcResult.Successed = false; plcResult.Message = "no connected"; return plcResult; } try { //plcResult.Result = Socket.Send(data); Socket.Send(data); } catch (Exception ex) { plcResult.Successed = false; plcResult.Message = ex.Message; plcResult.MessageDetail = ex.ToString(); Socket?.Close(); Socket = null; } return plcResult; } /// /// 异步发送 /// /// /// internal protected virtual PLCResult BeginSend(byte[] data) { PLCResult plcResult = new PLCResult(); if (data == null || data.Length == 0) { plcResult.Successed = false; plcResult.Message = "no command"; return plcResult; } if (Socket == null) { plcResult.Successed = false; plcResult.Message = "no socket"; return plcResult; } if (!Socket.Connected) { plcResult.Successed = false; plcResult.Message = "no connected"; return plcResult; } SocketAsyncState sas = new SocketAsyncState(); try { sas.Data = data; sas.Size = data.Length; sas.Result = plcResult; Socket.BeginSend(sas.Data, sas.Offset, sas.Size, SocketFlags.None, SendCallBack, sas); } catch (Exception ex) { plcResult.Successed = false; plcResult.Message = ex.Message; plcResult.MessageDetail = ex.ToString(); sas?.Close(); sas = null; Socket?.Close(); Socket = null; } sas?.WaitOne(); sas?.Close(); sas = null; return plcResult; } /// /// 发送结束 /// /// private void SendCallBack(IAsyncResult iar) { if (iar.AsyncState is SocketAsyncState sas) { try { sas.Offset += Socket.EndSend(iar); if (sas.Offset < sas.Size) { Socket.BeginSend(sas.Data, sas.Offset, sas.Size - sas.Offset, SocketFlags.None, SendCallBack, iar); } else { sas.Set(); } } catch (Exception ex) { sas.Result.Successed = false; sas.Result.Message = ex.Message; sas.Result.MessageDetail = ex.ToString(); Socket.Close(); Socket = null; sas.Set(); } } } #endregion #region Receive /// /// 接收 /// /// /// protected virtual PLCResult Receive(int length) { PLCResult plcResult = new PLCResult(new byte[length]); if (length == 0) { plcResult.Successed = false; plcResult.Message = "no length"; return plcResult; } if (Socket == null) { plcResult.Successed = false; plcResult.Message = "no socket"; return plcResult; } if (!Socket.Connected) { plcResult.Successed = false; plcResult.Message = "no connected"; return plcResult; } try { //plcResult.Result = Socket.Receive(plcResult.Data); //Socket.Receive(plcResult.Data); Socket.Receive(plcResult.Data, 0, length, SocketFlags.None); } catch (Exception ex) { plcResult.Successed = false; plcResult.Message = ex.Message; plcResult.MessageDetail = ex.ToString(); Socket?.Close(); Socket = null; } return plcResult; } /// /// 异步接收 /// /// /// protected virtual PLCResult BeginReceive(int length) { PLCResult plcResult = new PLCResult(new byte[length]); if (length == 0) { plcResult.Successed = false; plcResult.Message = "no length"; return plcResult; } if (Socket == null) { plcResult.Successed = false; plcResult.Message = "no socket"; return plcResult; } if (!Socket.Connected) { plcResult.Successed = false; plcResult.Message = "no connected"; return plcResult; } SocketAsyncState sas = new SocketAsyncState(); try { sas.Data = plcResult.Data; sas.Size = length; sas.Result = plcResult; Socket.BeginReceive(sas.Data, sas.Offset, sas.Size, SocketFlags.None, ReceiveCallback, sas); } catch (Exception ex) { plcResult.Successed = false; plcResult.Message = ex.Message; plcResult.MessageDetail = ex.ToString(); sas?.Close(); sas = null; Socket?.Close(); Socket = null; } sas?.WaitOne(); sas?.Close(); sas = null; return plcResult; } /// /// 接收结束 /// /// private void ReceiveCallback(IAsyncResult iar) { if (iar.AsyncState is SocketAsyncState sas) { try { int length = Socket.EndReceive(iar); if (length > 0) { sas.Offset += length; if (sas.Offset < sas.Size) { Socket.BeginReceive(sas.Data, sas.Offset, sas.Size - sas.Offset, SocketFlags.None, SendCallBack, iar); } else { sas.Set(); } } else { sas.Result.Successed = false; sas.Result.Message = "other socket has closed"; Socket.Close(); Socket = null; sas.Set(); } } catch (Exception ex) { sas.Result.Successed = false; sas.Result.Message = ex.Message; sas.Result.MessageDetail = ex.ToString(); Socket.Close(); Socket = null; sas.Set(); } } } #endregion } }