心跳
保持對連接有效性的檢測
TCP Keep-Alive 選項
TCP的keepalive是側重在保持客戶端和服務端的連接,一方會不定期發送心跳包給另一方,當一方端掉的時候,沒有斷掉的定時發送幾次心跳包,如果間隔發送幾次,對方都返回的是RST,而不是ACK,那么就釋放當前鏈接。設想一下,如果tcp層沒有keepalive的機制,一旦一方斷開連接卻沒有發送FIN給另外一方的話,那么另外一方會一直以為這個連接還是存活的,幾天,幾月。那么這對服務器資源的影響是很大的。
原理
如果開啟了 TCP 保活,需要考慮以下幾種情況:
- 第一種,當 TCP 保活的探測報文發送給對端, 對端會正常響應,這樣 TCP 保活時間會被重置。
- 第二種,對端程序崩潰并重啟。對端會產生一個 RST 報文,這樣很快就會發現 TCP 連接已經被重置。
- 第三種,是對端程序崩潰,或其他原因導致報文不可達,連續幾次達到保活探測次數后,TCP 會報告該 TCP 連接已經死亡。
TCP 保活機制默認是關閉的,當我們選擇打開時,可以分別在連接的兩個方向上開啟,也可以單獨在一個方向上開啟。如果開啟服務器端到客戶端的檢測,就可以在客戶端非正常斷連的情況下清除在服務器端保留的“臟數據”;而開啟客戶端到服務器端的檢測,就可以在服務器無響應的情況下,重新發起連接。
1.應用層探活
為什么這么做?
- eepalive只能檢測連接是否存活,不能檢測連接是否可用。例如,某一方發生了死鎖,無法在連接上進行任何讀寫操作,但是操作系統仍然可以響應網絡層keepalive包。
- TCP keepalive 機制依賴于操作系統的實現,靈活性不夠,默認關閉,且默認的 keepalive 心跳時間是 兩個小時, 時間較長。
- 代理(如socks proxy)、或者負載均衡器,會讓tcp keep-alive失效
基于此,我們往往需要加上應用層的心跳。
解決:通過在應用程序中模擬 TCP Keep-Alive 機制,來完成在應用層的連接探活。
- 設計一個 PING-PONG 的機制,需要保活的一方,比如客戶端,在保活時間達到后,發起對連接的 PING 操作,如果服務器端對 PING 操作有回應,則重新設置保活時間,否則對探測次數進行計數,如果最終探測次數達到了保活探測次數預先設置的值之后,則認為連接已經無效。
- 第一個是需要使用定時器,這可以通過使用 I/O 復用自身的機制來實現;第二個是需要設計一個 PING-PONG 的協議。
2.消息格式設計
我們的程序是客戶端來發起保活,為此定義了一個消息對象。這個消息對象是一個結構體,前 4 個字節標識了消息類型,為了簡單,這里設計了MSG_PING、MSG_PONG、MSG_TYPE 1和MSG_TYPE 2四種消息類型。
typedef struct {u_int32_t type;char data[1024]; } messageObject;#define MSG_PING 1 #define MSG_PONG 2 #define MSG_TYPE1 11 #define MSG_TYPE2 21總結:
雖然TCP 沒有提供系統的保活能力,讓應用程序可以方便地感知連接的存活,但是,可以在應用程序里靈活地建立這種機制這種機制的建立依賴于系統定時器,以及恰當的應用層報文協議。比如,使用心跳包就是這樣一種保持 Keep Alive 的機制。
問題:
1.探活是否同樣適用于 UDP 呢?
- UDP里面各方并不會維護一個socket上下文狀態是無連接的,如果為了連接而保活是不必要的,如果為了探測對端是否正常工作而做ping-pong也是可行的。
2.有人說額外的探活報文占用了有限的帶寬,對此你是怎么想的呢?而且,為什么需要多次探活才能決定一個 TCP 連接是否已經死亡呢?
- 還是很有必要判定存活 像以前網吧打游戲 朋友的電腦突然藍屏死機 朋友的角色還殘留于游戲中,所以服務器為了判定他是否真的存活還是需要一個心跳包 隔了一段時間過后把朋友角色踢下線
總結
- 上一篇: 使用tushare获取股票数据并计算历史
- 下一篇: 翻看了21天的公众号内容,只发现一个事实