守护线程
心跳包在服务端版Socket编程需要处理长时间没有发送数据的Socket,需要在超时多长时间后断开连接,我们需要独立一个线程(DaemonThread)来轮询,在执行断开时,需要把Socket对象锁定,并调用CloseClientSocket来断开连接,具体处理代码如下:
namespace SocketAsyncSvr { class DaemonThread : Object { private Thread m_thread; private AsyncSocketServer m_asyncSocketServer; public DaemonThread(AsyncSocketServer asyncSocketServer) { m_asyncSocketServer = asyncSocketServer; m_thread = new Thread(DaemonThreadStart); m_thread.Start(); } public void DaemonThreadStart() { while (m_thread.IsAlive) { AsyncSocketUserToken[] userTokenArray = null; m_asyncSocketServer.AsyncSocketUserTokenList.CopyList(ref userTokenArray); for (int i = 0; i < userTokenArray.Length; i++) { if (!m_thread.IsAlive) break; try { if ((DateTime.Now - userTokenArray[i].ActiveDateTime).Milliseconds > m_asyncSocketServer.SocketTimeOutMS) //超时Socket断开 { lock (userTokenArray[i]) { m_asyncSocketServer.CloseClientSocket(userTokenArray[i]); } } } catch (Exception E) { Program.Logger.ErrorFormat("Daemon thread check timeout socket error, message: {0}", E.Message); Program.Logger.Error(E.StackTrace); } } for (int i = 0; i < 60 * 1000 / 10; i++) //每分钟检测一次 { if (!m_thread.IsAlive) break; Thread.Sleep(10); } } } public void Close() { m_thread.Abort(); m_thread.Join(); } } }
有超时连接,相对应的需要设计心跳包,心跳包用来检测连接和维护连接状态,心跳包的原理是客户端发送一个包给服务器,服务器收到后发一个响应包给客户端,通过检测是否有返回来判断连接是否正常,心跳包实现放在BaseSocketProtocol.DoActive方法中。
public bool DoActive() { m_outgoingDataAssembler.AddSuccess(); return DoSendResult(); }
具体由各个协议是否决定调用,如控制协议ControlSocketProtocol实现心跳协议如下:
public override bool ProcessCommand(byte[] buffer, int offset, int count) //处理分完包的数据,子类从这个方法继承 { ControlSocketCommand command = StrToCommand(m_incomingDataParser.Command); m_outgoingDataAssembler.Clear(); m_outgoingDataAssembler.AddResponse(); m_outgoingDataAssembler.AddCommand(m_incomingDataParser.Command); if (!CheckLogined(command)) //检测登录 { m_outgoingDataAssembler.AddFailure(ProtocolCode.UserHasLogined, ""); return DoSendResult(); } if (command == ControlSocketCommand.Login) return DoLogin(); else if (command == ControlSocketCommand.Active) return DoActive(); else if (command == ControlSocketCommand.GetClients) return DoGetClients(); else { Program.Logger.Error("Unknow command: " + m_incomingDataParser.Command); return false; } }DEMO下载地址:http://download.csdn.net/detail/sqldebug_fan/7467745
免责声明:此代码只是为了演示C#完成端口编程,仅用于学习和研究,切勿用于商业用途。水平有限,C#也属于初学,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com。