本發(fā)明涉及心跳包控制技術(shù)領(lǐng)域,特別涉及一種心跳包異步控制方法及裝置。
背景技術(shù):
心跳包通常是客戶端每隔一小段時(shí)間向服務(wù)器發(fā)送的數(shù)據(jù)包,通知服務(wù)器自己仍然在線,并傳輸一些可能有必要的數(shù)據(jù),服務(wù)端收到后回復(fù)一個(gè)固定信息,如果服務(wù)端在規(guī)定的時(shí)間內(nèi)沒(méi)有收到客戶端信息則視客戶端斷開(kāi)。因按照一定的時(shí)間間隔發(fā)送,類(lèi)似于心跳,所以叫做心跳包。心跳包的內(nèi)容沒(méi)有特別規(guī)定,一般都是很小的包或者只是包含包頭的一個(gè)空包。
心跳包在可穿戴式設(shè)備與遠(yuǎn)程服務(wù)器通信當(dāng)中非常關(guān)鍵,因?yàn)槟壳按蟛糠执┐魇皆O(shè)備都是采用GRPS網(wǎng)絡(luò)與遠(yuǎn)程服務(wù)器進(jìn)行雙向通信,當(dāng)網(wǎng)絡(luò)運(yùn)營(yíng)商檢測(cè)到GPRS數(shù)據(jù)終端在一定時(shí)間內(nèi)沒(méi)有傳輸數(shù)據(jù),就會(huì)將該連接掐斷,因此需要一種機(jī)制,在用戶沒(méi)有數(shù)據(jù)收發(fā)的時(shí)候來(lái)保證連接不會(huì)被掐斷。心跳包的設(shè)置正是為了解決上述問(wèn)題,心跳包的設(shè)置也方便遠(yuǎn)程服務(wù)器進(jìn)行在線監(jiān)測(cè)。
目前有一種普遍的方法是采用TCP/IP協(xié)議層內(nèi)置的KeepAlive功能來(lái)實(shí)現(xiàn)心跳功能,不論是服務(wù)端還是客戶端,一方開(kāi)啟KeepAlive功能后,就會(huì)自動(dòng)在規(guī)定時(shí)間內(nèi)向?qū)Ψ桨l(fā)送心跳包,而另一方在收到心跳包后就會(huì)自動(dòng)回復(fù),以告訴對(duì)方我仍然在線。該機(jī)制簡(jiǎn)單可靠,但存在如下缺點(diǎn):SO_KEEPALIVE無(wú)法控制,它會(huì)每時(shí)每刻都發(fā);SO_KEEPALIVE設(shè)置空閑2小時(shí)才發(fā)送一個(gè)“保持存活探測(cè)分節(jié)”,不能保證實(shí)時(shí)檢測(cè),因此對(duì)于判斷網(wǎng)絡(luò)斷開(kāi)時(shí)間太長(zhǎng),對(duì)于需要及時(shí)響應(yīng)的程序不太適應(yīng)。當(dāng)然也可以修改時(shí)間間隔參數(shù),但是會(huì)影響到所有打開(kāi)此選項(xiàng)的套接口,關(guān)聯(lián)了完成端口的socket可能會(huì)忽略掉該套接字選項(xiàng)。另外比較常用的另一種方法是采用多線程,在接收和發(fā)送數(shù)據(jù)時(shí)個(gè)人設(shè)計(jì)一個(gè)守護(hù)進(jìn)程,定時(shí)發(fā)送Heart-Beat包,客戶端/服務(wù)器收到該小包后,立刻返回相應(yīng)的包即可檢測(cè)對(duì)方是否實(shí)時(shí)在線。但上述方法的缺點(diǎn)在于:對(duì)于操作系統(tǒng)而言,進(jìn)程和線程的開(kāi)辟,如果在線客戶端數(shù)量龐大,那么無(wú)論是客戶端的心跳包監(jiān)測(cè),還是例行的數(shù)據(jù)接收和發(fā)送,都要頻繁的開(kāi)辟和銷(xiāo)毀線程,這個(gè)對(duì)系統(tǒng)也是一種不小的開(kāi)銷(xiāo),而且編程比較復(fù)雜,難以保證多線程通信的同步,容易導(dǎo)致線程的死鎖。
技術(shù)實(shí)現(xiàn)要素:
本發(fā)明提供了一種心跳包異步控制方法及裝置,旨在至少在一定程度上解決現(xiàn)有技術(shù)中的上述技術(shù)問(wèn)題之一。
為了解決上述問(wèn)題,本發(fā)明提供了如下技術(shù)方案:
一種心跳包異步控制方法,其特征在于,包括:
步驟A:服務(wù)器套接字通信參數(shù)初始化及服務(wù)器通信模型初始化,建立監(jiān)聽(tīng)套接字描述符;
步驟B:建立和初始化服務(wù)器動(dòng)態(tài)鏈表;
步驟C:初始化并啟動(dòng)控制心跳包的系統(tǒng)定時(shí)器;
步驟D:調(diào)用監(jiān)聽(tīng)函數(shù),判斷是否有客戶端通信事件的觸發(fā),如果有客戶端通信事件的觸發(fā),則服務(wù)器主程序退出監(jiān)聽(tīng)函數(shù),服務(wù)器遍歷并處理通信事件;如果沒(méi)有客戶端通信事件的觸發(fā),則繼續(xù)等待客戶端通信事件的觸發(fā)。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:在所述步驟B中,建立的服務(wù)器動(dòng)態(tài)鏈表包括一個(gè)頭結(jié)點(diǎn)和若干結(jié)點(diǎn),每一個(gè)結(jié)點(diǎn)包括:客戶端數(shù)據(jù)域和存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域next,每個(gè)結(jié)點(diǎn)通過(guò)指針域next連接起來(lái)構(gòu)成一個(gè)動(dòng)態(tài)鏈表,所述結(jié)點(diǎn)的長(zhǎng)度等于當(dāng)前與服務(wù)器建立TCP連接的客戶端數(shù)量;所述客戶端數(shù)據(jù)域包括:存儲(chǔ)客戶端ID的字符數(shù)組類(lèi)型變量id,存儲(chǔ)服務(wù)器給當(dāng)前上線客戶端分配的socket文件描述符的整型變量fd,存儲(chǔ)丟失的心跳包個(gè)數(shù)的整型變量heartbeat_lost_count。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:所述步驟C還包括:?jiǎn)?dòng)定時(shí)器中斷服務(wù)函數(shù),通過(guò)定時(shí)器中斷服務(wù)函數(shù)對(duì)服務(wù)器動(dòng)態(tài)鏈表進(jìn)行遍歷,給每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count按照1的步進(jìn)遞增,對(duì)每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count的值進(jìn)行判斷,如果heartbeat_lost_count大于預(yù)設(shè)值,則服務(wù)器認(rèn)為該客戶端丟失心跳包的時(shí)間大于預(yù)設(shè)值,服務(wù)器根據(jù)客戶端的fd查找客戶端所在鏈表的結(jié)點(diǎn)位置,強(qiáng)制將客戶端所在的結(jié)點(diǎn)刪除掉,并給客戶端返回錯(cuò)誤信息,斷開(kāi)與所述客戶端的TCP連接。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:在所述步驟D中,所述監(jiān)聽(tīng)函數(shù)為epoll_wait函數(shù),所述客戶端通信事件包括:新的客戶端發(fā)起TCP連接請(qǐng)求、已經(jīng)建立連接的客戶端斷開(kāi)TCP連接的請(qǐng)求、已經(jīng)建立連接的客戶端有數(shù)據(jù)傳輸和已經(jīng)建立連接的客戶端異常斷開(kāi)TCP連接。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:在所述步驟D中,監(jiān)聽(tīng)函數(shù)發(fā)現(xiàn)觸發(fā)待處理的事件剛好等于監(jiān)聽(tīng)套接字描述符socket_fd;根據(jù)socket_fd調(diào)用accept函數(shù)返回新的socket套接字描述符;將偵聽(tīng)到的socket_fd通過(guò)epoll_ctl函數(shù)添加到epoll句柄當(dāng)中,已經(jīng)建立連接的新的客戶端如果后續(xù)有數(shù)據(jù)傳輸,系統(tǒng)利用socket_fd與該客戶端進(jìn)行雙向通信。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:在所述步驟D中,epoll_wait函數(shù)發(fā)現(xiàn)觸發(fā)待處理的事件為fd;根據(jù)fd調(diào)用read函數(shù);判斷read返回值是否大于0,如果不大于0,判斷read返回值是否等于0,如果read返回值等于0,根據(jù)發(fā)起斷開(kāi)請(qǐng)求的客戶端的fd查找結(jié)點(diǎn)所在位置并將結(jié)點(diǎn)從鏈表中刪除掉,然后將該刪除的結(jié)點(diǎn)的前后結(jié)點(diǎn)通過(guò)結(jié)點(diǎn)的指針域next連接起來(lái)構(gòu)成新的鏈表;如果read返回值不等于0,進(jìn)行異常處理;read返回值大于0,判斷數(shù)據(jù)包的格式,如果符合預(yù)定格式,則對(duì)分配給該客戶端的fd進(jìn)行提取,并將它們分別存儲(chǔ)到結(jié)點(diǎn)的id和fd當(dāng)中,將fd和id建立映射關(guān)系,將該結(jié)點(diǎn)添加到動(dòng)態(tài)鏈表的結(jié)尾;如果不符合預(yù)定格式,根據(jù)協(xié)議對(duì)其他數(shù)據(jù)包括或者命令進(jìn)行判斷并處理。
本發(fā)明實(shí)施例采取的另一技術(shù)方案為:一種心跳包異步控制裝置,包括:通信參數(shù)初始化模塊、通信模型初始化模塊、動(dòng)態(tài)鏈表初始化模塊、系統(tǒng)定時(shí)器啟動(dòng)及初始化模塊、監(jiān)聽(tīng)函數(shù)調(diào)用模塊,所述通信參數(shù)初始化模塊用于初始化服務(wù)器套接字通信參數(shù),建立監(jiān)聽(tīng)套接字描述符;所述通信模型初始化模塊用于初始化服務(wù)器通信模型;所述動(dòng)態(tài)鏈表初始化模塊用于建立和初始化服務(wù)器動(dòng)態(tài)鏈表;所述系統(tǒng)定時(shí)器啟動(dòng)及初始化模塊用于初始化并啟動(dòng)控制心跳包的系統(tǒng)定時(shí)器;所述監(jiān)聽(tīng)函數(shù)調(diào)用模塊用于調(diào)用監(jiān)聽(tīng)函數(shù),判斷是否有客戶端通信事件的觸發(fā),如果有客戶端通信事件的觸發(fā),服務(wù)器主程序退出監(jiān)聽(tīng)函數(shù),服務(wù)器遍歷并處理通信事件,如果沒(méi)有客戶端通信事件的觸發(fā),則繼續(xù)等待客戶端通信事件的觸發(fā)。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:所述服務(wù)器動(dòng)態(tài)鏈表包括一個(gè)頭結(jié)點(diǎn)和若干結(jié)點(diǎn),每一個(gè)結(jié)點(diǎn)包括兩部分:客戶端數(shù)據(jù)域和存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域next,每個(gè)結(jié)點(diǎn)通過(guò)指針域next連接起來(lái)構(gòu)成一個(gè)動(dòng)態(tài)鏈表,所述結(jié)點(diǎn)的長(zhǎng)度等于當(dāng)前與服務(wù)器建立TCP連接的客戶端數(shù)量。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:所述客戶端數(shù)據(jù)域包括:存儲(chǔ)客戶端ID的字符數(shù)組類(lèi)型變量id,存儲(chǔ)服務(wù)器給當(dāng)前上線客戶端分配的socket文件描述符的整型變量fd,存儲(chǔ)丟失的心跳包個(gè)數(shù)的整型變量heartbeat_lost_count。
本發(fā)明實(shí)施例采取的技術(shù)方案還包括:所述系統(tǒng)定時(shí)器啟動(dòng)及初始化模塊還用于啟動(dòng)定時(shí)器中斷服務(wù)函數(shù),通過(guò)定時(shí)器中斷服務(wù)函數(shù)對(duì)服務(wù)器動(dòng)態(tài)鏈表進(jìn)行遍歷,給每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count按照1的步進(jìn)遞增,對(duì)每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count的值進(jìn)行判斷,如果heartbeat_lost_count大于預(yù)設(shè)值,則服務(wù)器認(rèn)為該客戶端丟失心跳包的時(shí)間大于預(yù)設(shè)值,服務(wù)器將根據(jù)客戶端的fd查找客戶端所在鏈表的結(jié)點(diǎn)位置,強(qiáng)制將客戶端所在的結(jié)點(diǎn)刪除掉,并給客戶端返回錯(cuò)誤信息,斷開(kāi)與所述客戶端的TCP連接。
相對(duì)于現(xiàn)有技術(shù),本發(fā)明實(shí)施例產(chǎn)生的有益效果在于:本發(fā)明實(shí)施例的心跳包異步控制方法及裝置采用linux系統(tǒng)的Epoll服務(wù)器模型,簡(jiǎn)單可靠高效,克服了多線程編程和協(xié)議復(fù)雜的問(wèn)題,僅需一個(gè)進(jìn)程就可以實(shí)現(xiàn)數(shù)以萬(wàn)計(jì)的socket通信,此外,采用動(dòng)態(tài)鏈表的機(jī)制來(lái)實(shí)現(xiàn)客戶端上線管理和多客戶端心跳包監(jiān)測(cè),簡(jiǎn)單且靈活,因鏈表的長(zhǎng)度是跟隨用戶數(shù)量的變化而動(dòng)態(tài)的變化的,因此能夠充分利用系統(tǒng)內(nèi)存資源并高效地對(duì)心跳包數(shù)據(jù)進(jìn)行處理;客戶端發(fā)送心跳包的周期可變,針對(duì)某客戶端,服務(wù)器發(fā)送心跳包的周期與該客戶端發(fā)送心跳包的周期一致,如果因?yàn)榫W(wǎng)絡(luò)故障導(dǎo)致服務(wù)器在規(guī)定時(shí)間內(nèi)收不到某上線的客戶端的心跳包就將對(duì)該客戶端進(jìn)行斷線的處理。
附圖說(shuō)明
圖1是本發(fā)明實(shí)施例的心跳包異步控制方法的流程圖;
圖2是本發(fā)明實(shí)施例的維護(hù)客戶端通信的鏈表結(jié)構(gòu)示意圖;
圖3是心跳包監(jiān)測(cè)的定時(shí)器中斷服務(wù)函數(shù)的運(yùn)行流程圖;
圖4是本發(fā)明實(shí)施例的心跳包異步控制方法處理新的客戶端發(fā)起TCP連接請(qǐng)求的流程圖;
圖5是本發(fā)明實(shí)施例的心跳包異步控制方法處理已經(jīng)建立連接的客戶端斷開(kāi)TCP連接的請(qǐng)求或者已經(jīng)建立連接的客戶端發(fā)送上線和心跳包命令的事件的流程圖;
圖6是當(dāng)前在線的客戶端鏈表的示意圖;
圖7是有新的客戶端上線后的新鏈表示意圖;
圖8是已經(jīng)建立連接的客戶端發(fā)起斷開(kāi)請(qǐng)求的鏈表示意圖;
圖9是將發(fā)起斷開(kāi)請(qǐng)求的客戶端從鏈表中刪除并重構(gòu)鏈表的示意圖;
圖10是本發(fā)明實(shí)施例的心跳包異步控制裝置的結(jié)構(gòu)示意圖;
圖11是服務(wù)器壓力測(cè)試模擬示意圖;
圖12是客戶端的TCP/IP調(diào)試工具模擬示意圖;
圖13是上線客戶端信息顯示圖。
具體實(shí)施方式
為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點(diǎn)更加清楚明白,以下結(jié)合附圖及實(shí)施例,對(duì)本發(fā)明進(jìn)行進(jìn)一步詳細(xì)說(shuō)明。應(yīng)當(dāng)理解,此處所描述的具體實(shí)施例僅用以解釋本發(fā)明,并不用于限定本發(fā)明。
請(qǐng)參閱圖1,是本發(fā)明實(shí)施例的心跳包異步控制方法的流程圖。本發(fā)明實(shí)施例中的心跳包異步控制方法包括:
步驟10:服務(wù)器Socket通信參數(shù)初始化,建立監(jiān)聽(tīng)socket描述符socket_fd;
在步驟10中,Socket通常也稱作"套接字",用于描述IP地址和端口,是一個(gè)通信鏈的句柄,可以用來(lái)實(shí)現(xiàn)不同虛擬機(jī)或不同計(jì)算機(jī)之間的通信。
步驟20:服務(wù)器通信模型epoll初始化;
在步驟20中,epoll是一種高效的管理socket的模型。
步驟30:建立和初始化服務(wù)器動(dòng)態(tài)鏈表;
在步驟30中,建立的服務(wù)器動(dòng)態(tài)鏈表是僅包含頭結(jié)點(diǎn)的鏈表,用來(lái)對(duì)客戶端進(jìn)行維護(hù)管理,該鏈表的結(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)id_fd_node定義如下:
typedef struct id_fd_str
{
char id[13];//存儲(chǔ)ID的字符數(shù)組
int fd;//存儲(chǔ)Socket的fd
int heartbeat_lost_count;//存儲(chǔ)丟失的心跳包個(gè)數(shù)
struct id_fd_str*next;//存儲(chǔ)指向下一個(gè)結(jié)點(diǎn)的地址
}id_fd_node;
請(qǐng)一并參閱圖2,圖2是本發(fā)明實(shí)施例的維護(hù)客戶端通信的鏈表結(jié)構(gòu)示意圖。該鏈表包括一個(gè)頭結(jié)點(diǎn)和若干結(jié)點(diǎn),每一個(gè)結(jié)點(diǎn)包括兩部分:客戶端數(shù)據(jù)域和存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域next,每個(gè)結(jié)點(diǎn)通過(guò)指針域next連接起來(lái)構(gòu)成一個(gè)動(dòng)態(tài)鏈表,頭結(jié)點(diǎn)指向第一個(gè)結(jié)點(diǎn),第一個(gè)結(jié)點(diǎn)指向第二個(gè)結(jié)點(diǎn),依次類(lèi)推,最后一個(gè)結(jié)點(diǎn)不再指向其他結(jié)點(diǎn),因此指針域用”null”填充。結(jié)點(diǎn)的長(zhǎng)度等于當(dāng)前與服務(wù)器建立TCP連接的客戶端數(shù)量,客戶端數(shù)據(jù)域包括三部分:存儲(chǔ)客戶端ID的字符數(shù)組類(lèi)型變量id,存儲(chǔ)服務(wù)器給當(dāng)前上線客戶端分配的socket文件描述符的整型變量fd,存儲(chǔ)丟失的心跳包個(gè)數(shù)的整型變量heartbeat_lost_count。
步驟40:初始化并啟動(dòng)控制心跳包的系統(tǒng)定時(shí)器;
在步驟40中,啟動(dòng)控制心跳包的系統(tǒng)定時(shí)器后,會(huì)啟動(dòng)一個(gè)定時(shí)器中斷服務(wù)函數(shù),請(qǐng)一并參閱圖3,為心跳包監(jiān)測(cè)的定時(shí)器中斷服務(wù)函數(shù)的運(yùn)行流程圖。在定時(shí)器中斷服務(wù)函數(shù)中,對(duì)鏈表進(jìn)行遍歷,給每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count按照1的步進(jìn)遞增,然后對(duì)每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count的值進(jìn)行判斷,如果heartbeat_lost_count大于預(yù)設(shè)值,那么服務(wù)器認(rèn)為該客戶端丟失心跳包的時(shí)間大于預(yù)設(shè)值(流程圖中設(shè)為5),服務(wù)器將根據(jù)客戶端的fd查找客戶端所在鏈表的結(jié)點(diǎn)位置,強(qiáng)制將客戶端所在的結(jié)點(diǎn)刪除掉,那么動(dòng)態(tài)鏈表的結(jié)構(gòu)和長(zhǎng)度將發(fā)生變化,并給客戶端返回"connection time out!,please online again\r\n"的錯(cuò)誤信息,然后斷開(kāi)與該客戶端的TCP連接從而強(qiáng)制讓其下線。正常情況下,因?yàn)榉?wù)器會(huì)按照客戶端發(fā)心跳包的頻率給客戶端回應(yīng)心跳包(也就是客戶端的ID號(hào)),并將heartbeat_lost_count清零,因此定時(shí)器中斷服務(wù)函數(shù)中的heartbeat_lost_count是不會(huì)超過(guò)預(yù)設(shè)值的,只有因?yàn)榫W(wǎng)絡(luò)原因服務(wù)器接收不到客戶端的心跳包命令從而不能及時(shí)給heartbeat_lost_count清零,導(dǎo)致在定時(shí)器中斷服務(wù)函數(shù)中不斷的對(duì)heartbeat_lost_count遞增才會(huì)超過(guò)預(yù)設(shè)值。
步驟50:調(diào)用監(jiān)聽(tīng)函數(shù),判斷是否有客戶端通信事件的觸發(fā),如果有客戶端通信事件的觸發(fā),則進(jìn)入步驟60,如果沒(méi)有客戶端通信事件的觸發(fā),則進(jìn)入步驟80;
在步驟50中,調(diào)用監(jiān)聽(tīng)函數(shù)為epoll_wait函數(shù),客戶端通信事件包括:新的客戶端發(fā)起TCP連接請(qǐng)求、已經(jīng)建立連接的客戶端斷開(kāi)TCP連接的請(qǐng)求、已經(jīng)建立連接的客戶端有數(shù)據(jù)(命令)傳輸(包括上線命令和心跳包命令)、已經(jīng)建立連接的客戶端異常斷開(kāi)TCP連接。
步驟60:服務(wù)器主程序退出監(jiān)聽(tīng)函數(shù);
步驟70:服務(wù)器遍歷并處理通信事件;
步驟80:繼續(xù)等待客戶端通信事件的觸發(fā)。
在步驟80中,采用阻塞方式繼續(xù)等待客戶端通信事件的觸發(fā)。
請(qǐng)參閱圖4,是本發(fā)明實(shí)施例的心跳包異步控制方法處理新的客戶端發(fā)起TCP連接請(qǐng)求的流程圖。本發(fā)明實(shí)施例的心跳包異步控制方法處理新的客戶端發(fā)起TCP連接請(qǐng)求包括:
步驟100:epoll_wait函數(shù)發(fā)現(xiàn)觸發(fā)待處理的事件剛好等于監(jiān)聽(tīng)套接字描述符socket_fd;
步驟110:根據(jù)socket_fd調(diào)用accept函數(shù)返回新的socket套接字描述符(下文用fd表示);
步驟120:將偵聽(tīng)到的fd通過(guò)epoll_ctl函數(shù)添加到epoll句柄當(dāng)中,已經(jīng)建立連接的新的客戶端如果后續(xù)有數(shù)據(jù)傳輸,那么系統(tǒng)會(huì)利用fd與該客戶端進(jìn)行雙向通信。
請(qǐng)參閱圖5,是本發(fā)明實(shí)施例的心跳包異步控制方法處理已經(jīng)建立連接的客戶端斷開(kāi)TCP連接的請(qǐng)求或者已經(jīng)建立連接的客戶端發(fā)送上線和心跳包命令的事件的流程圖。本發(fā)明實(shí)施例的心跳包異步控制方法處理已經(jīng)建立連接的客戶端斷開(kāi)TCP連接的請(qǐng)求或者已經(jīng)建立連接的客戶端發(fā)送上線和心跳包命令的事件包括:
步驟400:epoll_wait函數(shù)發(fā)現(xiàn)觸發(fā)待處理的事件為fd(即已經(jīng)建立連接的客戶發(fā)起);
步驟401:根據(jù)fd調(diào)用read函數(shù);
步驟402:判斷read返回值是否大于0,如果不大于0,則進(jìn)入步驟403,如果大于0則進(jìn)入步驟404;
步驟403:判斷read返回值是否等于0,如果read返回值等于0,則進(jìn)入步驟411,如果read返回值不等于0,則進(jìn)入步驟412;
步驟404:判斷數(shù)據(jù)包是否為HEL HEL;xxxxxxxxxxx;@的格式,其中HEL是hello的縮寫(xiě),意思是向服務(wù)器打招呼,xxxxxxxxxxx是客戶端的ID(手機(jī)號(hào)),用分號(hào)";"隔開(kāi),最后以@結(jié)束,如果是則進(jìn)入步驟405,如果不是則進(jìn)入步驟407;
步驟405:服務(wù)器收到“HEL;xxxxxxxxxxx;@”的命令后,將會(huì)對(duì)xxxxxxxxxxx和分配給該客戶端的fd進(jìn)行提取,并將它們分別存儲(chǔ)到結(jié)點(diǎn)的id和fd當(dāng)中以便將fd和id建立映射關(guān)系,并對(duì)結(jié)點(diǎn)中的heartbeat_lost_count初始化為0;
步驟406:將該結(jié)點(diǎn)添加到動(dòng)態(tài)鏈表的結(jié)尾,至此,客戶端完成了與服務(wù)器連接并且上線的操作,那么動(dòng)態(tài)鏈表的結(jié)構(gòu)和長(zhǎng)度將發(fā)生變化(如圖6,圖7所示,圖6是當(dāng)前在線的客戶端鏈表的示意圖,圖7是有新的客戶端上線后的新鏈表示意圖,在圖6和圖7中,如果有新的客戶端發(fā)起上線操作,將重復(fù)剛才的流程,并在鏈表的結(jié)尾添加新的結(jié)點(diǎn))。
步驟407:判斷數(shù)據(jù)包是否為:HEART;xxxxxxxxxxx;@的格式,其中HEART為心跳包命令同步頭,xxxxxxxxxxx為客戶端的ID號(hào),如果是則進(jìn)入步驟408,否則進(jìn)入步驟410;
步驟408:根據(jù)客戶端的ID號(hào)查找該客戶端所在鏈表當(dāng)中的結(jié)點(diǎn)位置;
步驟409:將查找到的跟該客戶端對(duì)應(yīng)的結(jié)點(diǎn)中的heartbeat_lost_count清零;
步驟410:根據(jù)協(xié)議對(duì)其他數(shù)據(jù)包括或者命令進(jìn)行判斷并處理。
步驟411:根據(jù)發(fā)起斷開(kāi)請(qǐng)求的客戶端的fd查找結(jié)點(diǎn)所在位置并將結(jié)點(diǎn)從鏈表中刪除掉,然后將該刪除的結(jié)點(diǎn)的前后結(jié)點(diǎn)通過(guò)結(jié)點(diǎn)的指針域next連接起來(lái)構(gòu)成新的鏈表,假設(shè)刪除結(jié)點(diǎn)編號(hào)為2,那么刪除前后的鏈表變化如圖8和圖9表示。圖8是已經(jīng)建立連接的客戶端(結(jié)點(diǎn)2)發(fā)起斷開(kāi)請(qǐng)求的鏈表示意圖。圖9是將發(fā)起斷開(kāi)請(qǐng)求的客戶端(對(duì)應(yīng)結(jié)點(diǎn)2)從鏈表中刪除并重構(gòu)鏈表的示意圖。
步驟412:進(jìn)行異常處理。
請(qǐng)參閱圖10,是本發(fā)明實(shí)施例的心跳包異步控制裝置的機(jī)構(gòu)示意圖。本發(fā)明實(shí)施例中的心跳包異步控制裝置包括:通信參數(shù)初始化模塊、通信模型初始化模塊、動(dòng)態(tài)鏈表初始化模塊、系統(tǒng)定時(shí)器啟動(dòng)及初始化模塊、監(jiān)聽(tīng)函數(shù)調(diào)用模塊。
通信參數(shù)初始化模塊用于初始化服務(wù)器Socket通信參數(shù),建立監(jiān)聽(tīng)socket套接字描述符socket_fd。
通信模型初始化模塊用于初始化服務(wù)器通信模型epoll,其中,epoll是一種高效的管理socket的模型。
動(dòng)態(tài)鏈表初始化模塊用于建立和初始化服務(wù)器動(dòng)態(tài)鏈表。建立的服務(wù)器動(dòng)態(tài)鏈表是僅包含頭結(jié)點(diǎn)的鏈表,用來(lái)對(duì)客戶端進(jìn)行維護(hù)管理,該鏈表的結(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)id_fd_node定義如下:
typedef struct id_fd_str
{
char id[13];//存儲(chǔ)ID的字符數(shù)組
int fd;//存儲(chǔ)Socket的fd
int heartbeat_lost_count;//存儲(chǔ)丟失的心跳包個(gè)數(shù)
struct id_fd_str*next;//存儲(chǔ)指向下一個(gè)結(jié)點(diǎn)的地址
}id_fd_node;
請(qǐng)參閱圖2,圖2是本發(fā)明實(shí)施例的維護(hù)客戶端通信的鏈表結(jié)構(gòu)示意圖。該鏈表包括一個(gè)頭結(jié)點(diǎn)和若干結(jié)點(diǎn),每一個(gè)結(jié)點(diǎn)包括兩部分:客戶端數(shù)據(jù)域和存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域next,每個(gè)結(jié)點(diǎn)通過(guò)指針域next連接起來(lái)構(gòu)成一個(gè)動(dòng)態(tài)鏈表,頭結(jié)點(diǎn)指向第一個(gè)結(jié)點(diǎn),第一個(gè)結(jié)點(diǎn)指向第二個(gè)結(jié)點(diǎn),依次類(lèi)推,最后一個(gè)結(jié)點(diǎn)不再指向其他結(jié)點(diǎn),因此指針域用”null”填充。結(jié)點(diǎn)的長(zhǎng)度等于當(dāng)前與服務(wù)器建立TCP連接的客戶端數(shù)量,客戶端數(shù)據(jù)域包括三部分:存儲(chǔ)客戶端ID的字符數(shù)組類(lèi)型變量id,存儲(chǔ)服務(wù)器給當(dāng)前上線客戶端分配的socket文件描述符的整型變量fd,存儲(chǔ)丟失的心跳包個(gè)數(shù)的整型變量heartbeat_lost_count。
系統(tǒng)定時(shí)器啟動(dòng)及初始化模塊用于初始化并啟動(dòng)控制心跳包的系統(tǒng)定時(shí)器;啟動(dòng)控制心跳包的系統(tǒng)定時(shí)器后,系統(tǒng)定時(shí)器啟動(dòng)及初始化模塊會(huì)啟動(dòng)一個(gè)定時(shí)器中斷服務(wù)函數(shù)。請(qǐng)一并參閱圖3,為心跳包監(jiān)測(cè)的定時(shí)器中斷服務(wù)函數(shù)的運(yùn)行流程圖。在定時(shí)器中斷服務(wù)函數(shù)中,對(duì)鏈表進(jìn)行遍歷,給每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count按照1的步進(jìn)遞增,然后對(duì)每一個(gè)結(jié)點(diǎn)的heartbeat_lost_count的值進(jìn)行判斷,如果heartbeat_lost_count大于預(yù)設(shè)值,那么服務(wù)器認(rèn)為該客戶端丟失心跳包的時(shí)間大于預(yù)設(shè)值(流程圖中設(shè)為5),服務(wù)器將根據(jù)客戶端的fd查找客戶端所在鏈表的結(jié)點(diǎn)位置,強(qiáng)制將客戶端所在的結(jié)點(diǎn)刪除掉,那么動(dòng)態(tài)鏈表的結(jié)構(gòu)和長(zhǎng)度將發(fā)生變化,并給客戶端返回"connection time out!,please online again\r\n"的錯(cuò)誤信息,然后斷開(kāi)與該客戶端的TCP連接從而強(qiáng)制讓其下線。正常情況下,因?yàn)榉?wù)器會(huì)按照客戶端發(fā)心跳包的頻率給客戶端回應(yīng)心跳包(也就是客戶端的ID號(hào)),并將heartbeat_lost_count清零,因此定時(shí)器中斷服務(wù)函數(shù)中的heartbeat_lost_count是不會(huì)超過(guò)預(yù)設(shè)值的,只有因?yàn)榫W(wǎng)絡(luò)原因服務(wù)器接收不到客戶端的心跳包命令從而不能及時(shí)給heartbeat_lost_count清零,導(dǎo)致在定時(shí)器中斷服務(wù)函數(shù)中不斷的對(duì)heartbeat_lost_count遞增才會(huì)超過(guò)預(yù)設(shè)值。
監(jiān)聽(tīng)函數(shù)調(diào)用模塊用于調(diào)用監(jiān)聽(tīng)函數(shù),判斷是否有客戶端通信事件的觸發(fā),如果有客戶端通信事件的觸發(fā),服務(wù)器主程序退出監(jiān)聽(tīng)函數(shù),服務(wù)器遍歷并處理通信事件,如果沒(méi)有客戶端通信事件的觸發(fā),則繼續(xù)等待客戶端通信事件的觸發(fā)。
監(jiān)聽(tīng)函數(shù)調(diào)用模塊調(diào)用監(jiān)聽(tīng)函數(shù)為epoll_wait函數(shù),客戶端通信事件包括:新的客戶端發(fā)起TCP連接請(qǐng)求;已經(jīng)建立連接的客戶端斷開(kāi)TCP連接的請(qǐng)求;已經(jīng)建立連接的客戶端有數(shù)據(jù)(命令)傳輸(包括上線命令和心跳包命令);已經(jīng)建立連接的客戶端異常斷開(kāi)TCP連接。
請(qǐng)參閱圖11、圖12和圖13,圖11是服務(wù)器壓力測(cè)試模擬示意圖,圖12是客戶端的TCP/IP調(diào)試工具模擬示意圖,圖13是上線客戶端信息顯示圖。本發(fā)明實(shí)施例的心跳包異步控制方法及裝置通過(guò)TCP/IP調(diào)試工具來(lái)模擬客戶端,用其來(lái)發(fā)送上線命令和按一定周期發(fā)送心跳包,服務(wù)器能夠按照前面所述流程處理,上線信息顯示在前端web網(wǎng)頁(yè)當(dāng)中。
本發(fā)明實(shí)施例的心跳包異步控制方法及裝置通過(guò)在服務(wù)器維護(hù)著一個(gè)動(dòng)態(tài)鏈表,鏈表的長(zhǎng)度可彈性縮放,長(zhǎng)度取決與當(dāng)前在線(登陸)的客戶端數(shù)量,每一個(gè)結(jié)點(diǎn)代表著一個(gè)客戶端,一旦有新的客戶端發(fā)起TCP連接請(qǐng)求,就將其信息填充到新的結(jié)點(diǎn)并插入原鏈表的尾部,一旦已經(jīng)建立TCP連接的客戶端發(fā)起斷開(kāi)請(qǐng)求(包括主動(dòng)發(fā)起或者異常斷開(kāi)的情況),服務(wù)器就將其從鏈表結(jié)構(gòu)當(dāng)中剔除掉。由于鏈表的結(jié)點(diǎn)是根據(jù)需要?jiǎng)討B(tài)開(kāi)辟的,因此相比需要實(shí)現(xiàn)定義固定長(zhǎng)度的數(shù)組結(jié)構(gòu)而言,極大的提高內(nèi)存使用效率,由于是通過(guò)指針域操作鏈表的結(jié)點(diǎn),因此訪問(wèn)效率極高。滿足了服務(wù)器對(duì)于海量客戶端并發(fā)連接和并發(fā)通信的高速要求。
另外,定時(shí)器中斷服務(wù)函數(shù)觸發(fā)時(shí)間是等間隔的,不受任何客戶端心跳包周期的影響,不因客戶端心跳包周期的不同和變化,而且可以高速的對(duì)鏈表的結(jié)點(diǎn)進(jìn)行遍歷,及時(shí)的對(duì)異常斷開(kāi)的客戶端所在的結(jié)點(diǎn)進(jìn)行清理,從而將內(nèi)存回收再利用,因此可以實(shí)時(shí)監(jiān)測(cè)多客戶端的并發(fā)心跳包并進(jìn)行客戶端上下線管理。
為了提高服務(wù)器處理數(shù)據(jù)的實(shí)時(shí)性和增強(qiáng)CPU使用效率,服務(wù)器采用阻塞方式等待客戶端通信事件的觸發(fā),只要收到客戶端的心跳包,服務(wù)器立馬返回,因?yàn)榉?wù)器處理速度極快,因此,服務(wù)器給每一個(gè)客戶端回應(yīng)心跳包的頻率都可以不一樣,取決于并且等于該客戶端給服務(wù)器端發(fā)送心跳包的頻率。從而增強(qiáng)服務(wù)器對(duì)客戶端的兼容性。
客戶端每次上線系統(tǒng)分配的fd都是隨機(jī)的,具有不確定性,但是在系統(tǒng)中每一個(gè)客戶端的ID都是固定的,本系統(tǒng)通過(guò)上線命令和心態(tài)包命令,結(jié)合動(dòng)態(tài)鏈表的建立和操作,可以完美的將fd和用戶的ID動(dòng)態(tài)綁定起來(lái),無(wú)論客戶端在什么終端登錄,服務(wù)器都能夠識(shí)別。
本發(fā)明實(shí)施例的心跳包異步控制方法及裝置采用linux系統(tǒng)的Epoll服務(wù)器模型,簡(jiǎn)單可靠高效,克服了多線程編程和協(xié)議復(fù)雜的問(wèn)題,僅需一個(gè)進(jìn)程就可以實(shí)現(xiàn)數(shù)以萬(wàn)計(jì)的socket通信,此外,采用動(dòng)態(tài)鏈表的機(jī)制來(lái)實(shí)現(xiàn)客戶端上線管理和多客戶端心跳包監(jiān)測(cè),簡(jiǎn)單且靈活,因鏈表的長(zhǎng)度是跟隨用戶數(shù)量的變化而動(dòng)態(tài)的變化的,因此能夠充分利用系統(tǒng)內(nèi)存資源并高效地對(duì)心跳包數(shù)據(jù)進(jìn)行處理??蛻舳税l(fā)送心跳包的周期可變,針對(duì)某客戶端,服務(wù)器發(fā)送心跳包的周期與該客戶端發(fā)送心跳包的周期一致,如果因?yàn)榫W(wǎng)絡(luò)故障導(dǎo)致服務(wù)器在規(guī)定時(shí)間內(nèi)收不到某上線的客戶端的心跳包就將對(duì)該客戶端進(jìn)行斷線的處理。
對(duì)所公開(kāi)的實(shí)施例的上述說(shuō)明,使本領(lǐng)域?qū)I(yè)技術(shù)人員能夠?qū)崿F(xiàn)或使用本發(fā)明。對(duì)這些實(shí)施例的多種修改對(duì)本領(lǐng)域的專(zhuān)業(yè)技術(shù)人員來(lái)說(shuō)將是顯而易見(jiàn)的,本文中所定義的一般原理可以在不脫離本發(fā)明的精神或范圍的情況下,在其它實(shí)施例中實(shí)現(xiàn)。因此,本發(fā)明將不會(huì)被限制于本文所示的這些實(shí)施例,而是要符合與本文所公開(kāi)的原理和新穎特點(diǎn)相一致的最寬的范圍。