心跳包機制及Socket通訊服務的心跳包
心跳包之所以叫心跳包是因為:它像心跳一樣每隔固定時間發一次,以此來告訴伺服器,這個客戶端還活著。事實上這是為了保持長連線,至於這個包的內容,是沒有什麼特別規定的,不過一般都是很小的包,或者只包含包頭的一個空包。
在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&®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 +++++++++++++++++++ 伺服器的感覺系統