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