DSP

心跳包机制及Socket通信服务的心跳包

2019-07-13 12:54发布

本文转自http://www.cppblog.com/tx7do/archive/2009/11/09/100513.html  http://xue08161981.blog.163.com/blog/static/324996772009101010852137/  心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
    在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
    心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
    其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。
    在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。
    总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。   在一些系统中,经常用到客户端和服务器之间的通信,服务器要时刻知道客户端的网络连接状态,这大概就是所谓的“心跳包”。 下面是客户端心跳包核心代码: # region ++++++++++++++++++++ 客户端的感觉系统         //启动记时器         public void BeginTheTimer()         {             //th_UserLogin();             //这里只是要一个object类型数据,用它做为下面Timer的参数之一,没有其它意思             object myobject = (object)7;             //暂时设定为1秒钟启动一次!             System.Threading.Timer t = new System.Threading.Timer             (new System.Threading.TimerCallback(testTheNet), myobject, 1000, 1000);         }         //启动监视"已登录用户通信情况"的线程         public void testTheNet(object myobject)           {             //UserPassport up=new UserPassport();             Thread sendMyPulseThPro = new Thread(new ThreadStart(delegateSendMyPulse));             sendMyPulseThPro.Start();         }                    ///          /// 每隔1秒就是要来做这些事情的         ///          public void delegateSendMyPulse()         {             loginServer lser = new loginServer();             Login l = new Login();             l.Id = lser.MyLogin.Id;             l.ClientTypeVersion = version;             l.RequestType = 3;                       //3是确认联接正常的一个信号(让服务知道它与服务器的联接是正常的)             loginServer lserver = new loginServer();               //启动一个新线程去发送数据                       Thread thSendDat2 = new Thread             (new ParameterizedThreadStart(lserver.delgSendDataMethod));             thSendDat2.Start(l);             thSendDat2.IsBackground = true;             //标记我已经发送出去一次数据了             longinserver.MyLostTime += 1;             //如果外发了3次请求暗号后仍不见服务器的回应,则认为客户端已经与服务器断开联系了             if(longinserver.MyLostTime>=3)             {                 //停止Timer                 //告诉用户:“你已经与服务器失去联系了…………”                 longinserver.Controls["txtShowMsg"].Text = "You have lost the connect!";             }         } # endregion +++++++++++++++++++++ 客户端的感觉系统 下面是服务器端核心代码如下: # region +++++++++++++++++++++++ 服务器的感觉系统         //启动记时器         public void LoadTheTimer()         {              object o=(object)loginedCount++;             UserPassport up = new UserPassport();             //暂时设定为1秒钟启动一次!             System.Threading.Timer t = new System.Threading.Timer             (new System.Threading.TimerCallback(watchTheLoginUser), o, 1000, 1000);                                }         //启动监视"已登录用户通信情况"的线程         public void watchTheLoginUser(object o)         {             //UserPassport up=new UserPassport();             Thread checktheloginuser = new Thread(new ThreadStart(iAmAWatcher));             checktheloginuser.Start();         }         //真正做事的工人:这个工人的使命是每隔1秒钟后就查看一下登记薄         //registry里面有谁没有定时来向服务器报到了,如果出现谁三次检查都没有签到则除之名         public void iAmAWatcher()         {             this.txtLogin.Text += "@+";             int index = 0;             for (index = 0; index < loginedCount; index++)             {                 if (myRegistry[index].alive==false&®istry[index].studentID!="")                 {                     lock(this)                     {                         //坏(未到)记录增加一次                         myRegistry[index].no_check_in_count += 1;                                                        if (myRegistry[index].no_check_in_count >= 3)                         {                             //this.lblShowMsg.Text = "the student"                              //this.lblShowMsg.Text += registry[index].studentID.ToString()                              //this.lblShowMsg.Text += "is diaoxianle!";                             this.txtLogin.Text += "88";                             //标记该人已经与服务器失去连接了,因为他有连续3次的未到记录存在                             registry[index].studentID = "";                             registry[index].StudentName = "";                             registry[index].StudentIP = "";                             registry[index].status = 2;      //掉线                                                      }                     }                 }             }         }  //定时检查在线人目前状态 # endregion +++++++++++++++++++ 服务器的感觉系统