Part 10.網絡編程--TCP相關補充(十種狀態,2MSL問題,長短鏈接,listen隊列長度)

(一)TCP十種狀態數據庫

上一篇咱們學習了tcp三次握手和四次揮手的過程,其中設計到的狀態一共有10種,即爲下圖所示:後端

 

(二)TCP的2MSL問題服務器

2MSL兩倍的MSL,MSL即爲數據包在傳輸過程當中能夠存活的最長時間,TCP的TIME_WAIT狀態也稱爲2MSL等待狀態:當TCP的一端發起主動關閉,在發出最後一個ACK包後,即第3次握手完成後發送了第四次握手的ACK包後就進入了TIME_WAIT狀態,其必須在此狀態上停留兩倍的MSL時間,等待2MSL時間主要目的是怕最後一個 ACK包對方沒收到,那麼對方在超時後將重發第三次握手的FIN包,主動關閉端接到重發的FIN包後能夠再發一個ACK應答包。併發

在TIME_WAIT狀態時兩端的端口不能使用,要等到2MSL時間結束纔可繼續使用。app

當鏈接處於2MSL等待階段時任何遲到的報文段都將被丟棄。socket

不過在實際應用中能夠經過設置 SO_REUSEADDR選項達到沒必要等待2MSL時間結束再使用此端口。tcp

 

 (三)TCP的長短鏈接學習

1. TCP短鏈接

模擬一種TCP短鏈接的狀況:網站

  1. client 向 server 發起鏈接請求
  2. server 接到請求,雙方創建鏈接
  3. client 向 server 發送消息
  4. server 迴應 client
  5. 一次讀寫完成,此時雙方任何一個均可以發起 close 操做

 

在步驟5中,通常都是 client 先發起 close 操做。固然也不排除有特殊的狀況。spa

從上面的描述看,短鏈接通常只會在 client/server 間傳遞一次讀寫操做!

2. TCP長鏈接

再模擬一種長鏈接的狀況:

  1. client 向 server 發起鏈接
  2. server 接到請求,雙方創建鏈接
  3. client 向 server 發送消息
  4. server 迴應 client
  5. 一次讀寫完成,鏈接不關閉
  6. 後續讀寫操做...
  7. 長時間操做以後client發起關閉請求

 

3. TCP長/短鏈接的優勢和缺點

  • 長鏈接能夠省去較多的TCP創建和關閉的操做,減小浪費,節約時間。

    對於頻繁請求資源的客戶來講,較適用長鏈接。

  • client與server之間的鏈接若是一直不關閉的話,會存在一個問題:

    隨着客戶端鏈接愈來愈多,server遲早有扛不住的時候,這時候server端須要採起一些策略,如關閉一些長時間沒有讀寫事件發生的鏈接,這樣能夠避免一些惡意鏈接致使server端服務受損;若是條件再容許就能夠以客戶端機器爲顆粒度,限制每一個客戶端的最大長鏈接數,這樣能夠徹底避免某個蛋疼的客戶端連累後端服務。

  • 短鏈接對於服務器來講管理較爲簡單,存在的鏈接都是有用的鏈接,不須要額外的控制手段。
  • 但若是客戶請求頻繁,將在TCP的創建和關閉操做上浪費時間和帶寬。

4. TCP長/短鏈接的應用場景

  • 長鏈接多用於操做頻繁,點對點的通信,並且鏈接數不能太多狀況。

    每一個TCP鏈接都須要三次握手,這須要時間,若是每一個操做都是先鏈接,再操做的話那麼處理速度會下降不少,因此每一個操做完後都不斷開,再次處理時直接發送數據包就OK了,不用創建TCP鏈接。

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

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

 

 (四)listen的隊列長度

 

服務器端:

 1 from socket import *
 2 from time import sleep
 3 
 4 # 建立socket
 5 tcpSerSocket = socket(AF_INET, SOCK_STREAM)
 6 
 7 # 綁定本地信息
 8 address = ('', 7788)
 9 tcpSerSocket.bind(address)
10 
11 connNum = int(raw_input("請輸入要最大的連接數:"))
12 
13 # 使用socket建立的套接字默認的屬性是主動的,使用listen將其變爲被動的,這樣就能夠接收別人的連接了
14 tcpSerSocket.listen(connNum)
15 
16 while True:
17 
18     # 若是有新的客戶端來連接服務器,那麼就產生一個新的套接字專門爲這個客戶端服務器
19     newSocket, clientAddr = tcpSerSocket.accept()
20     print clientAddr
21     sleep(1)

 

客戶端:

1 from socket import *
2 
3 connNum = raw_input("請輸入要連接服務器的次數:")
4 for i in range(int(connNum)):
5     s = socket(AF_INET, SOCK_STREAM)
6     s.connect(("192.168.1.102", 7788))
7     print(i)

 

總結

  • listen中的black表示已經創建連接和半連接的總數
  • 若是當前已創建連接數和半連接數以達到設定值,那麼新客戶端就不會connect成功,而是等待服務器創建鏈接後留出空位
相關文章
相關標籤/搜索