守护线程
心跳包在服务端版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实现心跳协议如下:DEMO下载地址: http://download.csdn.net/detail/sqldebug_fan/7467745
- 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;
- }
- }
免责声明:此代码只是为了演示C#完成端口编程,仅用于学习和研究,切勿用于商业用途。水平有限,C#也属于初学,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com。