python socket 編程之三:長連接、短連接以及心跳


python socket 編程之三:長連接、短連接以及心跳

長連接:開啟一個socket連接,收發完數據后,不立刻關閉連接,可以多次收發數據包。

短連接:開啟一個socket連接,收發完數據后,立刻關閉連接。

心跳:長連接在沒有數據通信時,定時發送數據包(心跳),以維持連接狀態。

在python里,其實不用做那么復雜的事情,心跳檢測在TCP協議層會自動維護,python只需要調用接口設置就可以了,直接上代碼:

server端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#coding=utf-8
__author__  =  '葯師Aric'
'''
server端
長連接,短連接,心跳
'''
import  socket
BUF_SIZE  =  1024
host  =  'localhost'
port  =  8083
 
server  =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen( 1 #接收的連接數
client, address  =  server.accept()  #因為設置了接收連接數為1,所以不需要放在循環中接收
while  True #循環收發數據包,長連接
     data  =  client.recv(BUF_SIZE)
     print (data.decode())  #python3 要使用decode
     # client.close() #連接不斷開,長連接

client端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#coding=utf-8
__author__  =  '葯師Aric'
'''
client端
長連接,短連接,心跳
'''
import  socket
import  time
host  =  'localhost'
port  =  8083
client  =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE,  1 #在客戶端開啟心跳維護
client.connect((host, port))
while  True :
     client.send( 'hello world\r\n' .encode())
     print ( 'send data' )
     time.sleep( 1 #如果想驗證長時間沒發數據,SOCKET連接會不會斷開,則可以設置時間長一點

TCP心跳機制

心跳機制實現方式,基於TCP自帶的心跳包,TCP的SO_KEEPALIVE選項可以,系統默認的默認跳幀頻率為2小時,超過2小時后,本地的TCP 實現會發送一個數據包給遠程的 Socket. 如果遠程Socket 沒有發回響應, TCP實現就會持續嘗試 11 分鍾, 直到接收到響應為止。 否則就會自動斷開Socket連接。

TCP心跳的意義

TCP新手誤區–心跳的意義
背景
最近面試了很多的學生,發現很多TCP的新手對於TCP的使用有一些誤區,而這些坑也是當初我曾經疑惑過得地方。網上很少有文章對這些問題有過詳細的解析,即是有也只是直接給出結論和做法,沒有人將其中的來龍去脈講解清楚,所以我將這些問題的來龍去脈在這一系列的文章中講述出來,希望能讓廣大TCP的新手避開這些坑。

問題
我面試時經常會問的一個問題是當TCP兩端A、B建立了連接后,如果一端拔掉網線或者拔掉電源,那么另一端能夠收到通知嗎?
答案是不會,但是只有少數人能夠正確的回答這個問題。

原因
TCP是一種有連接的協議,但是這個連接並不是指有一條實際的電路,而是一種虛擬的電路。TCP的建立連接和斷開連接都是通過發送數據實現的,也就是我們常說的三次握手、四次揮手。TCP兩端保存了一種數據的狀態,就代表這種連接,TCP兩端之間的路由設備只是將數據轉發到目的地,並不知道這些數據實際代表了什么含義,也並沒有在其中保存任何的狀態信息,也就是說中間的路由設備沒有什么連接的概念,只是將數據轉發到目的地,只有數據的發送者和接受者兩端真正的知道傳輸的數據代表着一條連接。

但是這就說明了一點,如果不發送數據那么是無法斷開連接的。正常情況下當TCP的一端A調用了SOCKET的close或者進程結束,操作系統就會按照TCP協議發送FIN數據報文。B端收到后就會斷開連接。但是當出現了上文所說的異常情況時:被拔掉網線或者斷掉電源,總結起來就是沒有機會發出斷開的FIN數據報文。那么和A直連的路由設備雖然知道A設備已經斷開了,但是路由設備並沒有保存連接的狀態信息,所以路由設備也就不可能去通知B端A端的斷開。而B端沒有收到斷開的數據報文就會依然保持連接。所以A端拔掉網線或者斷掉電源后B端是沒辦法收到斷開連接的通知的。

解決方案
保持連接並不是毫無代價的,如果這種異常斷開的連接有很多,那么勢必會耗費大量的資源,必須要想辦法檢測出這種異常連接。
檢測的方法很簡單,只要讓B端主動通過這個連接向A端繼續發送數據即可。上文說過,A端異常斷開后,和A端直接連接的路由器是知道的。當B端發送的數據經過轉發后到達這個路由器后,必然最終會返回B端一個目的不可達。此時B端立刻就會知道這條連接其實已經異常斷開了。
但是B端不可能知道什么時候會出現這種異常,所以B端必須定時發送數據來檢測連接是否異常斷開。數據的內容無關緊要,任何數據都能達到這個效果。這個數據就是我們經常在TCP編程中所說的心跳。

KEEP_ALIVE
TCP協議本身就提供了一種這樣的機制來探測對端的存活。TCP協議有一個KEEP_LIVE開關,只要打開這個開關就會定時發送一些數據長度為零的探測心跳包,發送的頻率和次數都可以設置,具體的方法在網上搜索tcp keepalive即可,網上有很多文章,這里不再贅述。

應用層心跳
除了使用TCP協議本身的保活開關機制,還可以在應用層主動發送心跳數據包,那么在應用層主動發送心跳數據包的方式和TCP協議本身的保活機制有什么區別呢?

應用層的心跳數據包會耗費更多的帶寬,因為TCP協議的保活機制發送的是數據長度為零心跳包,而應用層的心跳數據包長度則必然會大於0。
應用層的心跳數據包可以帶一些應用所需要的數據,隨應用自己控制,而TCP協議的保活機制則是對於應用層透明的,無法利用心跳攜帶數據。
雙向心跳
那么是否只是一端向另一端發送心跳就行了呢?顯然不行。因為兩端都有可能發生異常斷開的情況。所以TCP連接的兩端必須都向對端發送心跳。

總結
TCP中不使用心跳通常來說並沒有什么問題,但是一旦遇到了連接異常斷開,那么就會出現問題。所以任何一個完善的TCP應用都應該使用心跳。
心跳的意義對於很多TCP的初學者而言是個大坑,我寫這篇文章希望初學者能夠在編寫TCP程序時避免這個坑,同時也希望面試者能夠深入理解TCP的心跳機制,能夠取得更好的面試結果。

test


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM