using System; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading; namespace Lskj.SocketService { /// /// 服务入口,建立Socket监听,负责接收连接,绑定连接对象,处理异步事件返回的接收和发送事件 /// public class AsyncSocketServer { private Socket _listenSocket; /// /// 最大支持连接个数 /// private int _numConnections; /// /// 每个连接接收缓存大小 /// private int _receiveBufferSize; /// /// 限制访问接收连接的线程数,用来控制最大并发数 /// private Semaphore _maxNumberAcceptedClients; /// /// Socket最大超时时间,单位为MS /// private int _socketTimeOutMS; public int SocketTimeOutMS { get { return _socketTimeOutMS; } set { _socketTimeOutMS = value; } } private AsyncSocketUserTokenPool _asyncSocketUserTokenPool; private AsyncSocketUserTokenList _asyncSocketUserTokenList; private LogOutputSocketProtocolMgr _logOutputSocketProtocolMgr; private UploadSocketProtocolMgr _uploadSocketProtocolMgr; private DownloadSocketProtocolMgr _downloadSocketProtocolMgr; /// /// 守护进程,用于关闭超时连接 /// private DaemonThread _daemonThread; /// /// 管理所有正在执行的AsyncSocketUserToken,是一个列表 /// /// The asynchronous socket user token list. public AsyncSocketUserTokenList AsyncSocketUserTokenList { get { return _asyncSocketUserTokenList; } } /// /// LogOutputSocketProtocol的管理对象 /// /// The log output socket protocol MGR. public LogOutputSocketProtocolMgr LogOutputSocketProtocolMgr { get { return _logOutputSocketProtocolMgr; } } /// /// UploadSocketProtocol的管理对象,用于检测是否同时上传同一个文件 /// /// The upload socket protocol MGR. public UploadSocketProtocolMgr UploadSocketProtocolMgr { get { return _uploadSocketProtocolMgr; } } /// /// DownloadSocketProtocol的管理对象 /// /// The download socket protocol MGR. public DownloadSocketProtocolMgr DownloadSocketProtocolMgr { get { return _downloadSocketProtocolMgr; } } /// /// 说明:处理Socket客户端发送的请求 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The source of the event. /// The instance containing the event data. private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs acceptEventArgs) { try { ProcessAccept(acceptEventArgs); } catch (Exception E) { Program.Logger.ErrorFormat("Accept client {0} error, message: {1}", acceptEventArgs.AcceptSocket, E.Message); Program.Logger.Error(E.StackTrace); } } /// /// 说明:完成异步操作的事件 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The source of the event. /// The instance containing the event data. /// The last operation completed on the socket was not a receive or send private void IO_Completed(object sender, SocketAsyncEventArgs asyncEventArgs) { AsyncSocketUserToken userToken = asyncEventArgs.UserToken as AsyncSocketUserToken; userToken.ActiveDateTime = DateTime.Now; try { lock (userToken) { if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive) ProcessReceive(asyncEventArgs); else if (asyncEventArgs.LastOperation == SocketAsyncOperation.Send) ProcessSend(asyncEventArgs); else throw new ArgumentException("The last operation completed on the socket was not a receive or send"); } } catch (Exception E) { Program.Logger.ErrorFormat("IO_Completed {0} error, message: {1}", userToken.ConnectSocket, E.Message); Program.Logger.Error(E.StackTrace); } } /// /// 说明:创建对应传输协议 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The user token. private void BuildingSocketInvokeElement(AsyncSocketUserToken userToken) { byte flag = userToken.ReceiveEventArgs.Buffer[userToken.ReceiveEventArgs.Offset]; if (flag == (byte)ProtocolFlag.Upload) userToken.AsyncSocketInvokeElement = new UploadSocketProtocol(this, userToken); else if (flag == (byte)ProtocolFlag.Download) userToken.AsyncSocketInvokeElement = new DownloadSocketProtocol(this, userToken); else if (flag == (byte)ProtocolFlag.RemoteStream) userToken.AsyncSocketInvokeElement = new RemoteStreamSocketProtocol(this, userToken); else if (flag == (byte)ProtocolFlag.Throughput) userToken.AsyncSocketInvokeElement = new ThroughputSocketProtocol(this, userToken); else if (flag == (byte)ProtocolFlag.Control) userToken.AsyncSocketInvokeElement = new ControlSocketProtocol(this, userToken); else if (flag == (byte)ProtocolFlag.LogOutput) userToken.AsyncSocketInvokeElement = new LogOutputSocketProtocol(this, userToken); if (userToken.AsyncSocketInvokeElement != null) { Program.Logger.InfoFormat("Building socket invoke element {0}.Local Address: {1}, Remote Address: {2}", userToken.AsyncSocketInvokeElement, userToken.ConnectSocket.LocalEndPoint, userToken.ConnectSocket.RemoteEndPoint); } } /// /// 说明:处理接收请求 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The instance containing the event data. private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs) { Program.Logger.InfoFormat("Client connection accepted. Local Address: {0}, Remote Address: {1}", acceptEventArgs.AcceptSocket.LocalEndPoint, acceptEventArgs.AcceptSocket.RemoteEndPoint); AsyncSocketUserToken userToken = _asyncSocketUserTokenPool.Pop(); _asyncSocketUserTokenList.Add(userToken); // 添加到正在连接列表 userToken.ConnectSocket = acceptEventArgs.AcceptSocket; userToken.ConnectDateTime = DateTime.Now; try { bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); // 投递接收请求 if (!willRaiseEvent) { lock (userToken) { ProcessReceive(userToken.ReceiveEventArgs); } } } catch (Exception E) { Program.Logger.ErrorFormat("Accept client {0} error, message: {1}", userToken.ConnectSocket, E.Message); Program.Logger.Error(E.StackTrace); } StartAccept(acceptEventArgs); //把当前异步事件释放,等待下次连接 } /// /// 说明:处理接收的套接字 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The instance containing the event data. private void ProcessReceive(SocketAsyncEventArgs receiveEventArgs) { AsyncSocketUserToken userToken = receiveEventArgs.UserToken as AsyncSocketUserToken; if (userToken.ConnectSocket == null) return; userToken.ActiveDateTime = DateTime.Now; if (userToken.ReceiveEventArgs.BytesTransferred > 0 && userToken.ReceiveEventArgs.SocketError == SocketError.Success) { int offset = userToken.ReceiveEventArgs.Offset; int count = userToken.ReceiveEventArgs.BytesTransferred; if ((userToken.AsyncSocketInvokeElement == null) & (userToken.ConnectSocket != null)) //存在Socket对象,并且没有绑定协议对象,则进行协议对象绑定 { BuildingSocketInvokeElement(userToken); offset = offset + 1; count = count - 1; } if (userToken.AsyncSocketInvokeElement == null) //如果没有解析对象,提示非法连接并关闭连接 { Program.Logger.WarnFormat("Illegal client connection. Local Address: {0}, Remote Address: {1}", userToken.ConnectSocket.LocalEndPoint, userToken.ConnectSocket.RemoteEndPoint); CloseClientSocket(userToken); } else { if (count > 0) //处理接收数据 { if (!userToken.AsyncSocketInvokeElement.ProcessReceive(userToken.ReceiveEventArgs.Buffer, offset, count)) { // 如果处理数据返回失败,则断开连接 CloseClientSocket(userToken); } else //否则投递下次介绍数据请求 { bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); //投递接收请求 if (!willRaiseEvent) ProcessReceive(userToken.ReceiveEventArgs); } } else { bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); //投递接收请求 if (!willRaiseEvent) ProcessReceive(userToken.ReceiveEventArgs); } } } else { CloseClientSocket(userToken); } } /// /// 说明:发送指令 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The instance containing the event data. /// true if XXXX, false otherwise. private bool ProcessSend(SocketAsyncEventArgs sendEventArgs) { AsyncSocketUserToken userToken = sendEventArgs.UserToken as AsyncSocketUserToken; if (userToken.AsyncSocketInvokeElement == null) return false; userToken.ActiveDateTime = DateTime.Now; if (sendEventArgs.SocketError == SocketError.Success) return userToken.AsyncSocketInvokeElement.SendCompleted(); //调用子类回调函数 else { CloseClientSocket(userToken); return false; } } public AsyncSocketServer(int numConnections) { _numConnections = numConnections; _receiveBufferSize = ProtocolConst.ReceiveBufferSize; _asyncSocketUserTokenPool = new AsyncSocketUserTokenPool(numConnections); _asyncSocketUserTokenList = new AsyncSocketUserTokenList(); _maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); _logOutputSocketProtocolMgr = new LogOutputSocketProtocolMgr(); _uploadSocketProtocolMgr = new UploadSocketProtocolMgr(); _downloadSocketProtocolMgr = new DownloadSocketProtocolMgr(); } /// /// 说明:初始化 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// public void Init() { AsyncSocketUserToken userToken; for (int i = 0; i < _numConnections; i++) // 按照连接数建立读写对象 { userToken = new AsyncSocketUserToken(_receiveBufferSize); userToken.ReceiveEventArgs.Completed += new EventHandler(IO_Completed); userToken.SendEventArgs.Completed += new EventHandler(IO_Completed); _asyncSocketUserTokenPool.Push(userToken); } } /// /// 说明:启动Socket服务监听 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The local end point. public void Start(IPEndPoint localEndPoint) { _listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _listenSocket.Bind(localEndPoint); _listenSocket.Listen(_numConnections); Program.Logger.InfoFormat("Start listen socket {0} success", localEndPoint.ToString()); StartAccept(null); _daemonThread = new DaemonThread(this); } /// /// 说明:释放异步事件 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The instance containing the event data. public void StartAccept(SocketAsyncEventArgs acceptEventArgs) { if (acceptEventArgs == null) { acceptEventArgs = new SocketAsyncEventArgs(); acceptEventArgs.Completed += new EventHandler(AcceptEventArg_Completed); } else { acceptEventArgs.AcceptSocket = null; // 释放上次绑定的Socket,等待下一个Socket连接 } _maxNumberAcceptedClients.WaitOne(); //获取信号量 bool willRaiseEvent = _listenSocket.AcceptAsync(acceptEventArgs); if (!willRaiseEvent) { ProcessAccept(acceptEventArgs); } } /// /// 说明:发送异步数据 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The connect socket. /// The instance containing the event data. /// The buffer. /// The offset. /// The count. /// true if XXXX, false otherwise. public bool SendAsyncEvent(Socket connectSocket, SocketAsyncEventArgs sendEventArgs, byte[] buffer, int offset, int count) { if (connectSocket == null) return false; sendEventArgs.SetBuffer(buffer, offset, count); bool willRaiseEvent = connectSocket.SendAsync(sendEventArgs); if (!willRaiseEvent) { return ProcessSend(sendEventArgs); } else return true; } /// /// 说明:关闭指定的Socket连接 /// 创建人:龚宇超 /// 创建日期:2018-01-24 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The user token. public void CloseClientSocket(AsyncSocketUserToken userToken) { if (userToken.ConnectSocket == null) return; string socketInfo = string.Format("Local Address: {0} Remote Address: {1}", userToken.ConnectSocket.LocalEndPoint, userToken.ConnectSocket.RemoteEndPoint); Program.Logger.InfoFormat("Client connection disconnected. {0}", socketInfo); try { userToken.ConnectSocket.Shutdown(SocketShutdown.Both); } catch (Exception E) { Program.Logger.ErrorFormat("CloseClientSocket Disconnect client {0} error, message: {1}", socketInfo, E.Message); } userToken.ConnectSocket.Close(); userToken.ConnectSocket = null; //释放引用,并清理缓存,包括释放协议对象等资源 _maxNumberAcceptedClients.Release(); _asyncSocketUserTokenPool.Push(userToken); _asyncSocketUserTokenList.Remove(userToken); } } }