心跳包機制及Socket通信服務的心跳包

本文轉自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();

        }  

        

        /// <summary>

        /// 每隔1秒就是要來做這些事情的

        /// </summary>

        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&&registry[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 +++++++++++++++++++ 服務器的感覺系統

發佈了8 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章