using System; using System.Collections.Generic; using System.ComponentModel; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; using Curtain.Net.Sockets.PLC.Model; namespace Curtain.Net.Sockets.PLC { /// /// Socket 服务端 /// public class SocketServer : PLCSocket { /// /// 在线客户端 /// //private Dictionary _factory = new Dictionary(); protected Dictionary clients = new Dictionary(); #region 属性 /// /// 服务所在winform窗体(异步事件响应用) /// public Control OwnerForm { get; set; } /// /// 服务状态 /// public bool Started { get; protected set; } /// /// 服务端模型 /// public virtual IServerModel Model { get { return null; } } /// /// 通信超时(毫秒) /// public int ReceiveTimeout { get; set; } /// /// 通信超时(毫秒) /// public int SendTimeout { get; set; } /// /// 服务端Session /// public ServerSession ServerSession { get; protected set; } /// /// 接收服务启动异常后自动重试次数 /// private int _repeated = 3; /// /// 接收服务启动异常后自动重试次数(默认3次,最大20次) /// public int Repeated { get { return _repeated; } set { if (value < 0) { _repeated = 0; } else if (value > 20) { _repeated = 20; } else { _repeated = value; } } } #endregion #region 构造 /// /// Socket 服务端 /// public SocketServer() { } #endregion #region 事件 /// /// 服务启动前 /// public event CancelEventHandler ServerStarting; /// /// 服务启动后 /// public event CancelEventHandler ServerStoping; /// /// 服务停止前 /// public event EventHandler ServerStarted; /// /// 服务停止后 /// public event EventHandler ServerStoped; /// /// 服务端事件发生 /// public event ServerMessageEventHandler ServerMessage; /// /// 服务启动前 /// protected virtual void OnServerStarting(CancelEventArgs e) { ServerStarting?.Invoke(this, e); } /// /// 服务启动后 /// protected virtual void OnServerStoping(CancelEventArgs e) { ServerStoping?.Invoke(this, e); } /// /// 服务停止前 /// protected virtual void OnServerStarted(EventArgs e) { ServerStarted?.Invoke(this, e); } /// /// 服务停止后 /// protected virtual void OnServerStoped(EventArgs e) { ServerStoped?.Invoke(this, e); } /// /// 服务端事件发生 /// protected virtual void OnServerMessage(ServerMessageEventArgs e) { if (OwnerForm?.InvokeRequired ?? false) { OwnerForm.BeginInvoke(new Action(OnServerMessage), e); return; } ServerMessage?.Invoke(this, e); } /// /// 完成数据接收 /// /// /// public delegate void ReceivedEventHandler(object sender, ReceiveSession e); /// /// 完成数据接收 /// public event ReceivedEventHandler Received; /// /// 完成数据接收 /// /// protected virtual void OnReceived(ReceiveSession rs) { //Framework.Log.Logger.Debug("OnReceived", "timeout"); if (OwnerForm?.InvokeRequired ?? false) { OwnerForm.BeginInvoke(new Action(OnReceived), rs); return; } Received?.Invoke(this, rs); } #endregion #region Accept /// /// 开始接收客户端消息 /// /// protected void AcceptCallback(IAsyncResult iar) { if (!this.Started || this.Socket == null) { // 服务器已停止 return; } if (iar.AsyncState is ServerSession ss) { if (ss == null || ss.Socket == null) { // 服务已停止 return; } Socket clientSocket = null; ClientSession cs = new ClientSession(); clients.Add(cs.ID, cs); try { clientSocket = ss.Socket.EndAccept(iar); cs.Server = ss; cs.Socket = clientSocket; try { cs.IPEndPoint = (IPEndPoint)clientSocket.RemoteEndPoint; } catch (Exception ex) { ServerMessageEventArgs e1 = new ServerMessageEventArgs { Type = ServerMessageType.Debug, Code = "CNS-D-001", Message = "客户端IP异常", Exception = ex, Client = cs, Server = ss }; this.OnServerMessage(e1); } ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-000", Message = $"客户端 {cs} 已连接", Client = cs, Server = ss }; this.OnServerMessage(e); ThreadPool.QueueUserWorkItem(new WaitCallback(OnClientConnected), cs); } catch (ObjectDisposedException ex) { // 服务已停止 OnServerDownError(ss, ex); return; } catch (Exception ex) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Error, Code = "CNS-E-000", Message = "客户端已关闭", Exception = ex, Client = cs, Server = ss }; this.OnServerMessage(e); //clientSocket?.Close(); CloseClientSocket(cs); } //如果失败,尝试重新启动 int i = 0; while (i < _repeated) { try { ss.Socket.BeginAccept(new AsyncCallback(AcceptCallback), ss); break; } catch (Exception ex) { i++; ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Error, Code = "CNS-E-001", Message = "服务启动失败,尝试重启( " + i + " / " + _repeated + " )", Exception = ex, Server = ss }; this.OnServerMessage(e); Thread.Sleep(1000); } } if (i >= _repeated) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Error, Code = "CNS-E-002", Message = "服务尝试重启失败", //e.Exception = ex; Server = ss }; this.OnServerMessage(e); this.StopCore(); } } } /// /// 开始接收 /// /// protected virtual void StartReceive(ClientSession cs) { if (!(cs.Socket.Connected)) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-002", Message = $"客户端 {cs} 已关闭", Client = cs, Server = cs.Server }; this.OnServerMessage(e); return; } int length = Model.HeadLength; if (length < 1) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Error, Code = "CNS-E-003", Message = Model.GetType().ToString() + ".HeadLength<1", Client = cs, Server = cs.Server }; this.OnServerMessage(e); return; } ReceiveSession rs = new ReceiveSession { ServerSocket = this, Client = cs, Offset = 0, Size = length }; try { rs.HeadBytes = new byte[length]; //cs.Socket.ReceiveTimeout = 0;//this.ReceiveTimeout; //Framework.Log.Logger.Debug("StartReceive", "timeout"); cs.Socket.BeginReceive(rs.HeadBytes, rs.Offset, rs.Size, SocketFlags.None, HeadReceiveCallback, rs); } catch (Exception ex) { //OnReceiveException(rs, ex); OnClientDown(rs, ex); } } /// /// 指令头接收方法 /// /// 异步状态信息 protected virtual void HeadReceiveCallback(IAsyncResult ar) { if (!this.Started || this.Socket == null) { // 服务器已停止 return; } //Framework.Log.Logger.Debug("HeadReceiveCallback=0", "timeout"); if (ar.AsyncState is ReceiveSession rs) { if (rs.Client == null || rs.Client.Socket == null) { // 服务器已停止 return; } try { int receiveCount = rs.Client.Socket.EndReceive(ar); //Framework.Log.Logger.Debug("HeadReceiveCallback-1:receiveCount="+ receiveCount, "timeout"); if (receiveCount == 0) { if (rs.Offset > 0) { OnClientTimeout(rs); } else { OnClientDown(rs); } return; } else { rs.Offset += receiveCount; } } catch (ObjectDisposedException) { // 客户端Socket已关闭(接收超时) //OnReceiveTimeout(rs); // 服务已停止 //OnServerDownError(rs.Client.Server, ex); return; } catch (SocketException ex) { // 已经断开连接了 //OnReceiveException(rs, ex); OnClientDown(rs, ex); return; } catch (Exception ex) { OnReceiveException(rs, ex, true); return; } if (rs.Offset < rs.Size) { try { // 继续接收,超时重启 //Framework.Log.Logger.Debug("HeadReceiveCallback-2:继续接收,超时重启", "timeout"); //rs.Client.Socket.ReceiveTimeout = this.ReceiveTimeout; //rs.Client.Socket.BeginReceive(rs.HeadBytes, rs.Offset, rs.Size - rs.Offset, // SocketFlags.None, HeadReceiveCallback, rs); rs.Client.Socket.BeginReceiveByTimeout(rs.HeadBytes, rs.Offset, rs.Size - rs.Offset, SocketFlags.None, HeadReceiveCallback, HeadReceiveCallbackTimeout, this.ReceiveTimeout, rs); } catch (Exception ex) { //OnReceiveException(rs, ex); OnClientDown(rs, ex); } return; } try { //rs.Head = ServerModel.ToCommandFromReceive(rs.HeadBytes); // 验证数据头 if (!Model.CheckHead(rs)) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Warning, Code = "CNS-W-000", Message = "接收的数据头格式不正确", Client = rs.Client, Server = rs.Client.Server }; CloseClientSocket(rs); this.OnServerMessage(e); return; } if (Model.FormatType == CommandFormatType.StartStopChar) { StringBuilder sbContent = new StringBuilder(); bool isEscapeChar = false; List listByte = new List(); try { while (true) { byte[] bytes = new byte[1]; rs.Client.Socket.ReceiveTimeout = this.ReceiveTimeout; int receiveCount = rs.Client.Socket.Receive(bytes, 0, 1, SocketFlags.None); if (receiveCount == 0) { OnClientDown(rs); return; } char[] chars = Encoding.ASCII.GetChars(bytes); if (!isEscapeChar) { if (chars[0] == this.Model.EscapeChar) { isEscapeChar = true; continue; } if (chars[0] == this.Model.StopChar) { break; } } isEscapeChar = false; listByte.AddRange(bytes); sbContent.Append(chars[0]); } rs.ContentBytes = listByte.ToArray(); rs.Content = sbContent.ToString(); StartReceive(rs.Client); OnReceived(rs); } catch (Exception ex) { OnClientDown(rs, ex); } return; } int length = Model.GetContentLength(rs); if (length > 0) { rs.Offset = 0; rs.Size = length; try { rs.ContentBytes = new byte[length]; // 正文接收,超时重启 //Framework.Log.Logger.Debug("HeadReceiveCallback-3:Content="+ length, "timeout"); //rs.Client.Socket.ReceiveTimeout = this.ReceiveTimeout; //rs.Client.Socket.BeginReceive(rs.ContentBytes, rs.Offset, rs.Size, // SocketFlags.None, ContentReceiveCallback, rs); rs.Client.Socket.BeginReceiveByTimeout(rs.ContentBytes, rs.Offset, rs.Size, SocketFlags.None, ContentReceiveCallback, ContentReceiveCallbackTimeout, this.ReceiveTimeout, rs); } catch (Exception ex) { //OnReceiveException(rs, ex); OnClientDown(rs, ex); } } else if (length < 0) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Warning, Code = "CNS-W-001", Message = "接收的数据头格式不正确(文本长度)", Client = rs.Client, Server = rs.Client.Server }; CloseClientSocket(rs); this.OnServerMessage(e); } else { StartReceive(rs.Client); OnReceived(rs); } } catch (Exception ex) { OnReceiveException(rs, ex); } } } /// /// 消息头接收超时 /// /// protected virtual void HeadReceiveCallbackTimeout(IAsyncResult ar) { if (!this.Started || this.Socket == null) { // 服务器已停止 return; } //Framework.Log.Logger.Debug("HeadReceiveCallbackTimeout:头接收超时", "timeout"); if (ar.AsyncState is ReceiveSession rs) { if (rs.Client == null || rs.Client.Socket == null) { // 服务器已停止 return; } OnReceiveTimeout(rs, true); } } /// /// 数据内容接收方法 /// /// protected virtual void ContentReceiveCallback(IAsyncResult ar) { if (!this.Started || this.Socket == null) { // 服务器已停止 return; } //Framework.Log.Logger.Debug("ContentReceiveCallback=0", "timeout"); if (ar.AsyncState is ReceiveSession rs) { if (rs.Client == null || rs.Client.Socket == null) { // 服务器已停止 return; } try { int receiveCount = rs.Client.Socket.EndReceive(ar); //Framework.Log.Logger.Debug("ContentReceiveCallback-1:receiveCount=" + receiveCount, "timeout"); if (receiveCount == 0) { if (rs.Offset > 0) { OnClientTimeout(rs); } else { OnClientDown(rs); } return; } else { rs.Offset += receiveCount; } } catch (ObjectDisposedException) { // 客户端Socket已关闭(接收超时) //OnReceiveTimeout(rs); // 服务已停止 //OnServerDownError(rs.Client.Server, ex); return; } catch (SocketException ex) { // 已经断开连接了 //OnReceiveException(rs, ex); OnClientDown(rs, ex); return; } catch (Exception ex) { OnReceiveException(rs, ex, true); return; } if (rs.Offset < rs.Size) { try { // 继续接收,超时重启 //Framework.Log.Logger.Debug("ContentReceiveCallback-2:继续接收,超时重启", "timeout"); //rs.Client.Socket.ReceiveTimeout = this.ReceiveTimeout; //rs.Client.Socket.BeginReceive(rs.ContentBytes, rs.Offset, rs.Size - rs.Offset, // SocketFlags.None, ContentReceiveCallback, rs); rs.Client.Socket.BeginReceiveByTimeout(rs.ContentBytes, rs.Offset, rs.Size - rs.Offset, SocketFlags.None, ContentReceiveCallback, ContentReceiveCallbackTimeout, this.ReceiveTimeout, rs); } catch (Exception ex) { //OnReceiveException(rs, ex); OnClientDown(rs, ex); } return; } rs.Content = Model.ToContentFromReceive(rs.ContentBytes); StartReceive(rs.Client); OnReceived(rs); } } /// /// 数据内容接收超时 /// /// protected virtual void ContentReceiveCallbackTimeout(IAsyncResult ar) { if (!this.Started || this.Socket == null) { // 服务器已停止 return; } //Framework.Log.Logger.Debug("ContentReceiveCallbackTimeout:正文接收超时", "timeout"); if (ar.AsyncState is ReceiveSession rs) { if (rs.Client == null || rs.Client.Socket == null) { // 服务器已停止 return; } OnReceiveTimeout(rs, false); } } #endregion #region 事件处理 /// /// 客户端上线 /// /// session protected virtual void OnClientConnected(object state) { if (state is ClientSession cs) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-001", Message = $"客户端 {cs} 已准备", Client = cs, Server = cs.Server }; this.OnServerMessage(e); this.StartReceive(cs); } } /// /// 服务接收异常 /// /// /// 异常信息 /// 异常信息 protected virtual void OnReceiveException(ReceiveSession rs, Exception ex, bool restart = false) { if (restart) { // 重启接收 StartReceive(rs.Client); ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Error, Code = "CNS-E-004", Message = $"服务端接收异常,重启客户端 {rs.Client} 连接", Exception = ex, Client = rs.Client, Server = rs.Client.Server }; this.OnServerMessage(e); } else { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Error, Code = "CNS-E-005", Message = $"服务端接收异常,关闭客户端 {rs.Client} 连接", Exception = ex, Client = rs.Client, Server = rs.Client.Server }; CloseClientSocket(rs); this.OnServerMessage(e); } } /// /// 客户端下线 /// /// /// protected virtual void OnClientDown(ReceiveSession rs, Exception ex = null) { //Framework.Log.Logger.Debug("OnClientDown", "timeout"); ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Client = rs.Client, Server = rs.Client.Server }; if (ex == null) { e.Code = "CNS-T-003"; e.Message = $"客户端 {rs.Client} 已下线"; } else { e.Code = "CNS-T-004"; e.Message = $"客户端 {rs.Client} 已下线(异常)"; e.Exception = ex; } CloseClientSocket(rs); this.OnServerMessage(e); } private void CloseClientSocket(ClientSession cs) { cs?.Socket?.Close(); cs?.Clear(); clients.Remove(cs.ID); } private void CloseClientSocket(ReceiveSession rs) { CloseClientSocket(rs.Client); } /// /// 客户端发送超时 /// /// protected virtual void OnClientTimeout(ReceiveSession rs) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-005", Message = $"客户端 {rs.Client} 发送超时", Client = rs.Client, Server = rs.Client.Server }; this.OnServerMessage(e); } /// /// 服务接收超时 /// /// /// protected virtual void OnReceiveTimeout(ReceiveSession rs, bool isHead) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-006", Message = $"接收客户端 {rs.Client} {(isHead ? "报文头" : "报文内容")}超时", Client = rs.Client, Server = rs.Client.Server }; //StartReceive(rs.Client); CloseClientSocket(rs); this.OnServerMessage(e); } /// /// 服务端异常下线 /// /// /// protected virtual void OnServerDownError(ServerSession ss, Exception ex) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Debug, Code = "CNS-D-000", Message = "服务端已关闭", Exception = ex, Server = ss }; this.OnServerMessage(e); } /// /// 回复消息 /// /// /// protected internal virtual void ReturnMessage(ReceiveSession rs, string message) { //Framework.Log.Logger.Debug("SetMessage", "timeout"); if (rs.Client == null || rs.Client.Socket == null) { // TO Message? return; } byte[] bs = Model.ToSendFromCommand(message); if (bs != null && bs.Length > 0) { try { rs.Client.Socket.SendTimeout = this.SendTimeout; rs.Client.Socket.Send(bs); } //catch (ObjectDisposedException ex) //{ // // 客户端Socket已关闭(接收超时) // //OnReceiveTimeout(rs); // // 服务已停止 // //OnServerDownError(rs.Client.Server, ex); // return; //} catch (SocketException ex) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-007", Message = $"发送客户端 {rs.Client} [{message}] 超时", Client = rs.Client, Server = rs.Client?.Server, Exception = ex }; this.OnServerMessage(e); } catch (Exception ex) { ServerMessageEventArgs e = new ServerMessageEventArgs { Type = ServerMessageType.Trace, Code = "CNS-T-008", Message = $"发送客户端 {rs.Client} [{message}] 异常", Client = rs.Client, Server = rs.Client?.Server, Exception = ex }; this.OnServerMessage(e); } } } #endregion #region Start & Stop /// /// 启动服务 /// /// 端口号 public virtual void Start(int port) { Start(port, null); } /// /// 启动服务 /// /// 端口号 /// 挂起连接队列的最大长度 public virtual void Start(int port, int backlog) { Start(port, null, backlog); } /// /// 启动服务 /// /// 端口号 /// IP地址 /// 挂起连接队列的最大长度 public virtual void Start(int port, IPAddress ipAddress, int backlog = 100) { if (!Started) { CancelEventArgs e = new CancelEventArgs(); this.OnServerStarting(e); if (e.Cancel) { return; } IPEndPoint ipEndPoint = new IPEndPoint(ipAddress ?? IPAddress.Any, port); ServerSession ss = new ServerSession { IPEndPoint = ipEndPoint, Backlog = backlog, }; this.CreateSocket(); //this.Socket.ReceiveTimeout = this.ReceiveTimeout; this.Socket.Bind(ipEndPoint); this.Socket.Listen(ss.Backlog); ss.Socket = this.Socket; //AcceptResult = this.Socket.BeginAccept(new AsyncCallback(AcceptCallback), ss); this.Socket.BeginAccept(new AsyncCallback(AcceptCallback), ss); this.Started = true; this.ServerSession = ss; this.OnServerStarted(EventArgs.Empty); } } //IAsyncResult AcceptResult = null; /// /// 关闭服务器的引擎 /// public virtual void Stop() { if (Started) { CancelEventArgs e = new CancelEventArgs(); this.OnServerStoping(e); if (e.Cancel) { return; } this.StopCore(); } } /// /// 停止服务 /// protected virtual void StopCore() { this.ServerSession?.Clear(); this.ServerSession = null; this.Started = false; this.Close(); this.Socket = null; //this.Socket.EndAccept(AcceptResult); foreach (ClientSession item in clients.Values) { item.Socket?.Close(); item.Clear(); } clients.Clear(); this.OnServerStoped(EventArgs.Empty); } /// /// 销毁 /// public override void Dispose() { try { this.StopCore(); } catch { } base.Dispose(); } #endregion } /// /// Socket 服务端 /// public class SocketServer : SocketServer where TServerModel : IServerModel, new() { #region 属性 /// /// 服务端模型 /// public override IServerModel Model { get { return this.ServerModel as IServerModel; } } /// /// 服务端模型 /// public TServerModel ServerModel { get; protected set; } #endregion #region 构造 /// /// Socket 服务端 /// public SocketServer(bool newModel = false) { if (newModel) { ServerModel = new TServerModel(); } else { ServerModel = PLC.Model.ServerModel.CreateModel(); } this.ReceiveTimeout = this.ServerModel.ReceiveTimeout; this.SendTimeout = this.ServerModel.SendTimeout; } /// /// Socket 服务端 /// /// 新实例 public SocketServer(TServerModel model) { if (model == null) { throw new NullReferenceException("ServerSocket TServerModel"); } ServerModel = model; this.ReceiveTimeout = this.ServerModel.ReceiveTimeout; this.SendTimeout = this.ServerModel.SendTimeout; } #endregion } }