長鏈接和端鏈接和心跳包機制

TCP鏈接簡介
當網絡通訊時採用TCP協議時,在真正的讀寫操做以前,server與client之間必須創建一個鏈接,
當讀寫操做完成後,雙方再也不須要這個鏈接時它們能夠釋放這個鏈接,
鏈接的創建是須要三次握手的,而釋放則須要4次握手,
因此說每一個鏈接的創建都是須要資源消耗和時間消耗的
​經典的三次握手示意圖:​


python

經典的四次握手關閉圖:linux

 



1、長鏈接與短鏈接
長鏈接: 指在一個TCP鏈接上能夠連續發送多個數據包,
        在TCP鏈接保持期間,若是沒有數據包發送,須要雙方發檢測包以維持此鏈接;
        通常須要本身作在線維持。 
短鏈接: 指通訊雙方有數據交互時,就創建一個TCP鏈接,數據發送完成後,則斷開此TCP鏈接;
        通常銀行都使用短鏈接。 
        它的優勢是:管理起來比較簡單,存在的鏈接都是有用的鏈接,不須要額外的控制手段 

好比http的,只是鏈接、請求、關閉,過程時間較短,服務器如果一段時間內沒有收到請求便可關閉鏈接。 
其實長鏈接是相對於一般的短鏈接而說的,也就是長時間保持客戶端與服務端的鏈接狀態。

長鏈接與短鏈接的操做過程 
一般的短鏈接操做步驟是: 
  鏈接→數據傳輸→關閉鏈接;

而長鏈接一般就是: 
  鏈接→數據傳輸→保持鏈接(心跳)→數據傳輸→保持鏈接(心跳)→……→關閉鏈接; 

這就要求長鏈接在沒有數據通訊時,定時發送數據包(心跳),以維持鏈接狀態,
短鏈接在沒有數據傳輸時直接關閉就好了

何時用長鏈接,短鏈接?
長鏈接多用於操做頻繁,點對點的通信,並且鏈接數不能太多狀況。
每一個TCP鏈接都須要三步握手,這須要時間,若是每一個操做都是先鏈接,再操做的話那麼處理速度會下降不少,
因此每一個操做完後都不斷開,下次次處理時直接發送數據包就OK了,不用創建TCP鏈接。

例如:數據庫的鏈接用長鏈接, 
若是用短鏈接頻繁的通訊會形成socket錯誤,並且頻繁的socket 建立也是對資源的浪費。

2、發送接收方式
一、異步 
報文發送和接收是分開的,相互獨立的,互不影響。這種方式又分兩種狀況: 
(1)異步雙工:接收和發送在同一個程序中,由兩個不一樣的子進程分別負責發送和接收 
(2)異步單工:接收和發送是用兩個不一樣的程序來完成。 

二、同步 
報文發送和接收是同步進行,既報文發送後等待接收返回報文。 
同步方式通常須要考慮超時問題,即報文發出去後不能無限等待,須要設定超時時間,
超過該時間發送方再也不等待讀返回報文,直接通知超時返回。
 
在長鏈接中通常是沒有條件可以判斷讀寫何時結束,因此必需要加長度報文頭。
讀函數先是讀取報文頭的長度,再根據這個長度去讀相應長度的報文。

三. 單工、半雙工和全雙工
根據通訊雙方的分工和信號傳輸方向可將通訊分爲三種方式:
單工、
半雙工、
全雙工。

在計算機網絡中主要採用雙工方式,其中:
局域網採用半雙工方式,
城域網和廣域網採用全雙年方式。   

1. 單工(Simplex)方式:
通訊雙方設備中發送器與接收器分工明確,只能在由發送器向接收器的單一固定方向上傳送數據。
採用單工通訊的典型發送設備如早期計算機的讀卡器,典型的接收設備如打印機。   

2. 半雙工(Half Duplex)方式:
通訊雙方設備既是發送器,也是接收器,兩臺設備能夠相互傳送數據,但某一時刻則只能向一個方向傳送數據。
例如,步話機是半雙工設備,由於在一個時刻只能有一方說話。   

3. 全雙工(Full Duplex)方式:
通訊雙方設備既是發送器,也是接收器,兩臺設備能夠同時在兩個方向上傳送數據。
例如,電話是全雙工設備,由於雙方可同時說話。

而像WEB網站的http服務通常都用短連接,由於長鏈接對於服務端來講會耗費必定的資源,
而像WEB網站這麼頻繁的成千上萬甚至上億客戶端的鏈接用短鏈接會更省一些資源,
若是用長鏈接,並且同時有成千上萬的用戶,若是每一個用戶都佔用一個鏈接的話,那可想而知吧。
因此併發量大,但每一個用戶無需頻繁操做狀況下需用短連好。

總之,長鏈接和短鏈接的選擇要視狀況而定。git

心跳包機制github

   跳包之因此叫心跳包是由於:它像心跳同樣每隔固定時間發一次,以此來告訴服務器,這個客戶端還活着。事實上這是爲了保持長鏈接,至於這個包的內容,是沒有什麼特別規定的,不過通常都是很小的包,或者只包含包頭的一個空包。
    在TCP的機制裏面,自己是存在有心跳包的機制的,也就是TCP的選項:SO_KEEPALIVE。系統默認是設置的2小時的心跳頻率。可是它檢查不到機器斷電、網線拔出、防火牆這些斷線。並且邏輯層處理斷線可能也不是那麼好處理。通常,若是隻是用於保活仍是能夠的。
    心跳包通常來講都是在邏輯層發送空的echo包來實現的。下一個定時器,在必定時間間隔下發送一個空包給客戶端,而後客戶端反饋一個一樣的空包回來,服務器若是在必定時間內收不到客戶端發送過來的反饋包,那就只有認定說掉線了。
    其實,要斷定掉線,只須要send或者recv一下,若是結果爲零,則爲掉線。可是,在長鏈接下,有可能很長一段時間都沒有數據往來。理論上說,這個鏈接是一直保持鏈接的,可是實際狀況中,若是中間節點出現什麼故障是難以知道的。更要命的是,有的節點(防火牆)會自動把必定時間以內沒有數據交互的鏈接給斷掉。在這個時候,就須要咱們的心跳包了,用於維持長鏈接,保活。
    在獲知了斷線以後,服務器邏輯可能須要作一些事情,好比斷線後的數據清理呀,從新鏈接呀……固然,這個天然是要由邏輯層根據需求去作了。
    總的來講,心跳包主要也就是用於長鏈接的保活和斷線處理。通常的應用下,斷定時間在30-40秒比較不錯。若是實在要求高,那就在6-9秒。
數據庫

 

心跳檢測步驟
1 客戶端每隔一個時間間隔發生一個探測包給服務器
2 客戶端發包時啓動一個超時定時器
3 服務器端接收到檢測包,應該回應一個包
4 若是客戶機收到服務器的應答包,則說明服務器正常,刪除超時定時器
5 若是客戶端的超時定時器超時,依然沒有收到應答包,則說明服務器掛了
編程

 

TCP keep-alive的三個參數

用man命令,能夠查看linux的tcp的參數:bash

man 7 tcp

其中keep-alive相關的參數有三個:服務器

tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
              The number of seconds between TCP keep-alive probes.

       tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
              The  maximum  number  of  TCP  keep-alive  probes  to send before giving up and killing the connection if no
              response is obtained from the other end.

       tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
              The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes.   Keep-
              alives  are  sent only when the SO_KEEPALIVE socket option is enabled.  The default value is 7200 seconds (2
              hours).  An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval
              of 75 seconds apart) when keep-alive is enabled.

這些的默認配置值在/proc/sys/net/ipv4 目錄下能夠找到。微信

能夠直接用cat來查看文件的內容,就能夠知道配置的值了。
也能夠經過sysctl命令來查看和修改:網絡

# 查詢
cat /proc/sys/net/ipv4/tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_time
#修改
sysctl net.ipv4.tcp_keepalive_time=3600

上面三個是系統級的配置,在編程時有三個參數對應,能夠覆蓋掉系統的配置:

TCP_KEEPCNT 覆蓋  tcp_keepalive_probes,默認9(次)
TCP_KEEPIDLE 覆蓋 tcp_keepalive_time,默認7200(秒)
TCP_KEEPINTVL 覆蓋 tcp_keepalive_intvl,默認75(秒)
 ```

## tcp keep-alive的本質
###TCP keep-alive probe
上面瞭解了tcp keep-alive的一些參數,下面來探究下其本質。

在遠程機器192.168.66.123上,用nc啓動一個TCP服務器:
```bash
nc -l 9999

在本地機器上,用python建立一個socket去鏈接,而且用wireshark抓包分析

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)

s.connect(('192.168.66.123', 9999))

上面的程序,設置了TCP_KEEPIDLE爲20,TCP_KEEPINTVL爲1,系統默認的tcp_keepalive_probes是9。

當網絡正常,不作干擾時,wireshark抓包的數據是這樣的(注意看第二列Time):

tcp-keepalive-good.png

能夠看到,當3次握手完成以後,每隔20秒以後66.120發送了一個TCP Keep-Alive的數據包,而後66.123迴應了一個TCP Keep-Alive ACK包。這個就是TCP keep-alive的實現原理了。

當發送了第一個TCP Keep-Alive包以後,撥掉192.168.66.123的網線,而後數據包是這樣子的:
tcp-keepalive-bad.png

能夠看到,當遠程服務器192.168.66.123網絡失去鏈接以後,本地機器(192.168.66.120)每隔一秒重發了9次tcp keep-alive probe,最終認爲這個TCP鏈接已經失效,發了一個RST包給192.168.66.123。

在本地機器上,用python建立一個socket去鏈接,而且用wireshark抓包分析
```python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)

s.connect(('192.168.66.123', 9999))

上面的程序,設置了TCP_KEEPIDLE爲20,TCP_KEEPINTVL爲1,系統默認的tcp_keepalive_probes是9。

當網絡正常,不作干擾時,wireshark抓包的數據是這樣的(注意看第二列Time):

tcp-keepalive-good.png

能夠看到,當3次握手完成以後,每隔20秒以後66.120發送了一個TCP Keep-Alive的數據包,而後66.123迴應了一個TCP Keep-Alive ACK包。這個就是TCP keep-alive的實現原理了。

當發送了第一個TCP Keep-Alive包以後,撥掉192.168.66.123的網線,而後數據包是這樣子的:
tcp-keepalive-bad.png

能夠看到,當遠程服務器192.168.66.123網絡失去鏈接以後,本地機器(192.168.66.120)每隔一秒重發了9次tcp keep-alive probe,最終認爲這個TCP鏈接已經失效,發了一個RST包給192.168.66.123。

爲何應用層須要heart beat/心跳包?

默認的tcp keep-alive超時時間太長

默認是7200秒,也就是2個小時。

socks proxy會讓tcp keep-alive失效

socks協議只管轉發TCP層具體的數據包,而不會轉發TCP協議內的實現細節的包(也作不到),參考socks_proxy

因此,一個應用若是使用了socks代理,那麼tcp keep-alive機制就失效了,因此應用要本身有心跳包。

socks proxy只是一個例子,真實的網絡很複雜,可能會有各類緣由讓tcp keep-alive失效。

移動網絡須要信令保活

前兩年,微信信令事件很火,搜索下「微信 信令」或者「移動網絡 信令」能夠查到不少相關文章。

這裏附上一個連接:微信的大規模使用真的會過多佔用信令,影響通信穩定嗎?

總結

  • TCP keep-alive是經過在空閒時發送TCP Keep-Alive數據包,而後對方迴應TCP Keep-Alive ACK來實現的。

  • 爲何須要heart beat/心跳包?由於tcp keep-alive不能知足人們的實時性的要求,就是這麼簡單。

相關文章
相關標籤/搜索