TCP的socket本身就是長連接的,那么為什么還要心跳包呢?
在smack里有個30s發送一個空消息的線程,同樣關於心跳包(keepalive)
據網絡搜索到的資料解釋如下
- 內網機器如果不主動向外發起連接,外網機沒法直連內網的,這也是內網機安全的原因之一,又因為路由器會把這個關系記錄下來,但是過一段時間這個記錄可能會丟失 ,所有每一個客戶端每隔一定時間就會向服務器發送消息,以保證服務器可以隨時找到你,這東西被稱為心跳包。
- 理論上說,這個連接是一直保持連接的,但是實際情況中,如果中間節點出現什么故障是難以知道的。更要命的是,有的節點(防火牆)會自動把一定時間之內沒有數據交互的連接給斷掉。在這個時候,就需要我們的心跳包了,用於維持長連接,保活。在獲知了斷線之后,服務器邏輯可能需要做一些事情,比如斷線后的數據清理,重新連接……當然,這個自然是要由邏輯層根據需求去做了。總的來說,心跳包主要也就是用於長連接的保活和斷線處理。一般的應用下,判定時間在30-40秒比較不錯。如果實在要求高,那就在6-9秒。
- 如果不主動關閉socket的話,系統不會自動關閉的,除非當前進程掛掉了,操作系統把占用的socket回收了才會關閉。為什么需要心跳連接主要是判斷當前連接是否是有效的、可被使用的。在實際應用中假設一段時間沒有數據傳輸時候理論上說應該連接是沒有問題的,但是網絡復雜,中途出現問題也是常見的,網線被掐斷了、對方進程掛掉了、頻繁丟包等,這時候TCP連接是不可使用的,但是對於應用層並不知道,如果需知道網絡情況則要很復雜的超時進行了解,TCP從底層就實現了這樣的功能。心跳機制是TCP在一段時間間隔后發送確認連接端是否還存在,如果存在的話就會回傳一個包確定網絡有效,如果心跳包有問題,則通知上層應用當前網絡有問題了。
- 這取決於你的server端的超時配置, 每個socket連接都是長連接,它是一個相當占用系統資源的通信管道, 如果這個長連接什么事也沒干硬是要占着資源,則server端可以選擇關閉這個連接,以省下資源讓更多的用戶連接進來。
- 所以,即便客戶端的是采用死循環while(true)方式連到服務端,對於特定的客戶端和服務端類型來說也需要一定時間間隔的心跳(告訴服務端,我還活着,雖然我沒干活也沒說話,但別把我關了)
以前開發手機游戲時,索愛有一款手機有強制要求,客戶端如果超過三分鍾無消息發向網絡服務端,則會在客戶端自動地強制把socket關斷。因為socket長連接相對於手機這樣資源少的設備來說是寶貴的資源。 (這個強制是指客戶端系統自動關的,不是我們代碼close的)
- 在TCP的機制里面,本身是存在有心跳包的機制的,也就是TCP的選項:SO_KEEPALIVE。系統默認是設置的2小時的心跳頻率。但是它檢查不到機器斷電、網線拔出、防火牆這些斷線。而且邏輯層處理斷線可能也不是那么好處理。一般,如果只是用於保活還是可以的。
- 心跳包一般來說都是在邏輯層發送空的echo包來實現的。下一個定時器,在一定時間間隔下發送一個空包給客戶端,然后客戶端反饋一個同樣的空包回來,服務器如果在一定時間內收不到客戶端發送過來的反饋包,那就只有認定說掉線了。
- 其實,要判定掉線,只需要send或者recv一下,如果結果為零,則為掉線。
以下是Smack里發送心跳包的代碼:PacketWrite.java

另外記一個CSDN上早些年的問題:
- QQ等程序聊天,雙方是否使用SOCKET通信?應該不會都是通過服務器吧,那樣服務器負擔得多大啊?
- 如果是SOCKET,那么多的好友,一下子得建立多少個啊?還得考慮上線下線隱身等亂七八糟的問題。
- 請高手幫忙指點一下這種復雜程序的結構,謝謝。
我還是很有發言權的呀,我畢業設計就是寫的這個(不過當時用的是vc寫的,帶文件傳輸的)@hl_ghost
我來說下我的思路吧:
1.如何知道誰在線?
Server維護一個list就ok了(存所有人的ip,名字,在線等)
2.如何讓服務器隨時能找到你?
前提:內網機器如果不主動向外發起連接,外網機沒法直連內網的,這也是內網機安全的原因之一吧,又因為路由器會把這個關系記錄下來,但是過一段時間這個記錄可能會丟失 ,所有每一個客戶端 每隔一定時間就會向服務器發送消息,以保證服務器可以隨時找到你,這東西被稱為心跳包。
3.如何跨內網直連
Nat打洞(難):
我簡單說下原理,有兩個客戶端A,B ,當然必須有Server啦(他可以隨時連接A,B)
當A想連B時,A就回從Server那要B的ip,然后與B建立連接(第一次不能成功的,因為看紅字)。
這時A告訴Server,我找不到B,你替我告訴他一聲,我想與它連接,服務器就告訴B,你給A下一個請帖(B發請求向A)!
這時A再向B發起連接就可以成功了(以后就不用server幫忙了)。
4.如何保證數據的可靠性(難)
滑動窗口協議,這個一句話兩句說不清楚啦,自己google下。
5是否在線。
我的設計是每隔40秒客戶端把Server中存自己的信息中的在線改為真,而服務器每過45秒就檢查這個在線變量是否為真,真的話把他改成假,如果假的話就說明這個人在45秒沒有向Server報到=>他網絡出現異常了,掉線了,向其它人發這個人的掉線通知。(這么設計原因在於當用戶網斷了沒有發下線通知,我們也能知道他不在線了)
6文件傳輸(難)
把文件讀到buf里,然后每次發1024b(當收到接收方確認后再發下一個1024b)。