一、TCP簡介 1、TCP介紹 TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議。 TCP通信需要經過創建連接、數據傳送、終止連接三個步驟。 TCP通信模型中,在通信開始之前,一定要先建立 ...
一、TCP簡介
1、TCP介紹
TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議。
TCP通信需要經過創建連接、數據傳送、終止連接三個步驟。
TCP通信模型中,在通信開始之前,一定要先建立相關的鏈接,才能發送數據,類似於生活中,"打電話"。
2、TCP面向連接
通信雙方必須先建立連接才能進行數據的傳輸,雙方都必須為該連接分配必要的系統內核資源,以管理連接的狀態和連接上的傳輸。
雙方間的數據傳輸都可以通過這一個連接進行。
完成數據交換後,雙方必須斷開此連接,以釋放系統資源。
這種連接是一對一的,因此TCP不適用於廣播的應用程式,基於廣播的應用程式請使用UDP協議。
3、TCP可靠傳輸
1)TCP採用發送應答機制
TCP發送的每個報文段都必須得到接收方的應答才認為這個TCP報文段傳輸成功
2)超時重傳
發送端發出一個報文段之後就啟動定時器,如果在定時時間內沒有收到應答就重新發送這個報文段。TCP為了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設為已丟失將會被進行重傳。
3)錯誤校驗
TCP用一個校驗和函數來檢驗數據是否有錯誤;在發送和接收時都要計算校驗和。
4) 流量控制和阻塞管理
流量控制用來避免主機發送得過快而使接收方來不及完全收下。
4、TCP與UDP的不同點
- 面向連接(確認有創建三方交握,連接已創建才作傳輸。)
- 有序數據傳輸
- 重發丟失的數據包
- 捨棄重覆的數據包
- 無差錯的數據傳輸
- 阻塞/流量控制
二、TCP數據包格式
所謂三次握手(Three-way Handshake),是指建立一個TCP連接時,需要客戶端和伺服器總共發送3個數據包。
那麼我們就先來看一下TCP數據包的格式:
在TCP層,有個FLAGS欄位,這個欄位有以下幾個標識:SYN, FIN, ACK, PSH, RST, URG.
- URG—為1表示高優先順序數據包,緊急指針欄位有效。
- ACK—為1表示確認號欄位有效
- PSH—為1表示是帶有PUSH標誌的數據,指示接收方應該儘快將這個報文段交給應用層而不用等待緩衝區裝滿。
- RST—為1表示出現嚴重差錯。可能需要重現創建TCP連接。還可以用於拒絕非法的報文段和拒絕連接請求。
- SYN—為1表示這是連接請求或是連接接受請求,用於創建連接和使順序號同步
- FIN—為1表示發送方沒有數據要傳輸了,要求釋放連接,
- Seq---序號,這是為了連接以後傳送數據用的,
- Ack---確認號對收到的數據包的確認,值是等待接收的數據包的序列號+1。
三、TCP的三次握手
三次握手的目的是連接伺服器指定埠,建立TCP連接,並同步連接雙方的序列號和確認號並交換 TCP 視窗大小信息.在socket編程中,客戶端執行connect()時。將觸發三次握手。
三次握手示意圖
第一次握手:(Client向Server發送聯機請求)
SYN=1(Client向Server發送聯機請求)
Client想要與Server進行TCP通信,首先他需要向Server發送一個SYN=1的同步序列編號(syncsynchronized squsequence number)用來表示建立連接,並且隨機產生一個數Seq number = X的數據包到Server,Server由於SYN=1知道,Client要求建立聯機,到這裡第一次握手就結束了
第二次握手:(Server向Client回覆聯機並確認聯機信息)
SYN=1(Server接受Client的聯機請求)
ACK=1(確認信息)
這是對第一次握手信息的確認,表示Server收到了Client的第一次握手信息
Ack=X+1(確認回覆)
同時Server回覆Client一個確認碼Ack表示你的聯機請求我已經收到,而且數據沒有丟失,怎麼驗證數據沒有丟失呢?即Ack的值等於Client發過來Seq的值加1,即Ack = X+1。因為我都知道你發過來的Seq的值,所以這個數據包沒有丟失。
Seq = Y(第二次握手的數據包序列號)
Server給Client的數據包序列號,為了數據包在到達Client之後的驗證,所以這次從Server到Client的數據包中同樣也會隨機產生一個Seq number = Y,
第三次握手
ACK=1(對第二次握手的確認)
首先Client會打開Server發送過來的Ack驗證一下是否正確為Seq+1,即第一次發送的seq number+1,確認無誤後,Client仍然需要給Server再次回覆確認即ACK=1
Seq=Z(第三次握手的數據包序列號)
Ack=Y+1
Client告訴Server,你給我回覆的信息我也收到了,怎麼確定我收到了你的信息呢?就是通過Ack等於第二次握手傳遞過來的Seq值+1。到此為止三次握手結束進入ESTABLISHED狀態,開始進行數據傳輸。
四、TCP四次揮手
第一次揮手發送FIN請求,第一次揮手結束。
第二次揮手開始,被動方向主動方發送ACK確認碼,到這裡第二次揮手結束。
第三次握手開始被動方向主動方發送FIN號結束。
第四次揮手開始主動方向被動方發送ACK確認,等待2MSL後斷開TCP連接。
五、TCP的十種狀態
這十種狀態分別是三次握手和四次揮手中的狀態,在上面兩個圖中都給大家標記出來了,這裡再給大家一個簡單的圖表示
六、TCP的2MSL問題
在四次揮手中我們提到了時間等待狀態,等待的時間是2MSL。
2MSL即兩倍的MSL,TCP的TIME_WAIT狀態也稱為2MSL等待狀態,
當TCP的一端發起主動關閉,在發出最後一個ACK包後,即第3次揮手完成後發送了第四次揮手的ACK包後就進入了TIME_WAIT狀態,必須在此狀態上停留兩倍的MSL時間,等待2MSL時間主要目的是怕最後一個 ACK包對方沒收到,那麼對方在超時後將重發第三次揮手的FIN包,主動關閉端接到重發的FIN包後可以再發一個ACK應答包。在TIME_WAIT狀態時兩端的埠不能使用,要等到2MSL時間結束才可繼續使用。當連接處於2MSL等待階段時任何遲到的報文段都將被丟棄。不過在實際應用中可以通過設置 SO_REUSEADDR選項達到不必等待2MSL時間結束再使用此埠。
七、TCP長連接和短連接
TCP在真正的讀寫操作之前,server與client之間必須建立一個連接,
當讀寫操作完成後,雙方不再需要這個連接時它們可以釋放這個連接,
連接的建立通過三次握手,釋放則需要四次握手,
所以說每個連接的建立都是需要資源消耗和時間消耗的。
1. TCP短連接
模擬一種TCP短連接的情況:
- client 向 server 發起連接請求
- server 接到請求,雙方建立連接
- client 向 server 發送消息
- server 回應 client
- 一次讀寫完成,此時雙方任何一個都可以發起 close 操作
在第 步驟5中,一般都是 client 先發起 close 操作。當然也不排除有特殊的情況。從上面的描述看,短連接一般只會在 client/server 間傳遞一次讀寫操作!
2. TCP長連接
再模擬一種長連接的情況:
- client 向 server 發起連接
- server 接到請求,雙方建立連接
- client 向 server 發送消息
- server 回應 client
- 一次讀寫完成,連接不關閉
- 後續讀寫操作...
- 長時間操作之後client發起關閉請求
3. TCP長/短連接操作過程
(1)短連接的操作步驟是:建立連接——數據傳輸——關閉連接...建立連接——數據傳輸——關閉連接
(2) 長連接的操作步驟是:建立連接——數據傳輸...(保持連接)...數據傳輸——關閉連接
4. TCP長/短連接的優點和缺點
-
長連接可以省去較多的TCP建立和關閉的操作,減少浪費,節約時間。對於頻繁請求資源的客戶來說,較適用長連接。
-
client與server之間的連接如果一直不關閉的話,會存在一個問題,隨著客戶端連接越來越多,server早晚有扛不住的時候,這時候server端需要採取一些策略,如關閉一些長時間沒有讀寫事件發生的連接,這樣可以避免一些惡意連接導致server端服務受損;如果條件再允許就可以以客戶端機器為顆粒度,限制每個客戶端的最大長連接數,這樣可以完全避免某個蛋疼的客戶端連累後端服務。
- 短連接對於伺服器來說管理較為簡單,存在的連接都是有用的連接,不需要額外的控制手段。但如果客戶請求頻繁,將在TCP的建立和關閉操作上浪費時間和帶寬。
5. TCP長/短連接的應用場景
-
長連接多用於操作頻繁,點對點的通訊,而且連接數不能太多情況。每個TCP連接都需要三次握手,這需要時間,如果每個操作都是先連接,再操作的話那麼處理速度會降低很多,所以每個操作完後都不斷開,再次處理時直接發送數據包就OK了,不用建立TCP連接。
例如:資料庫的連接用長連接,如果用短連接頻繁的通信會造成socket錯誤,而且頻繁的socket 創建也是對資源的浪費。
-
而像WEB網站的http服務一般都用短鏈接,因為長連接對於服務端來說會耗費一定的資源,而像WEB網站這麼頻繁的成千上萬甚至上億客戶端的連接用短連接會更省一些資源,如果用長連接,而且同時有成千上萬的用戶,如果每個用戶都占用一個連接的話,那可想而知吧。所以併發量大,但每個用戶無需頻繁操作情況下需用短連好。
八、TCP的通信模型
tcp通信模型中,在通信開始之前,一定要先建立相關的鏈接,才能發送數據,類似於生活中,"打電話"
生活中的電話機,如果想讓別人能更夠打通咱們的電話獲取相應服務的話,需要做一下幾件事情:
- 買個手機
- 插上手機卡
- 設計手機為正常接聽狀態(即能夠響鈴)
- 靜靜的等著別人撥打
tcp伺服器如同上面的電話機過程一樣,在程式中,如果想要完成一個tcp伺服器的功能,需要的流程如下:
- 創建一個socket套接字
- bind綁定ip和port
- listen使套接字變為可以被動鏈接
- accept等待客戶端的鏈接
- recv/send接收發送數據
九、TCP伺服器代碼實現
#coding = utf-8 from socket import * #1、創建socket套接字 tcpServerSocket = socket(AF_INET,SOCK_STREAM) #2、綁定本地信息 address = ("",7788) tcpServerSocket.bind(address) #3、使用socket創建的套接字預設的屬性是主動的,使用listen將其變為被動,這樣就可以等著別人鏈接了 tcpServerSocket.listen(5) """ 如果有新的客戶端來鏈接伺服器,那麼就產生一個新的套接字專門為這個客戶端伺服器 newSocket用來為這個客戶端服務 tcpServerSocket就可以省下來專門等待其他的客戶端的鏈接 """ newSocket,clientAddress = tcpServerSocket.accept() #4、接收對象發送過來的數據,最大接收1024個位元組 reveiveData = newSocket.recv(1024) print("接收的數據為:%s"%reveiveData.decode()) #5、發送數據到客戶端 newSocket.send("haha".encode()) #6、關閉為這個客戶端服務的套接字 newSocket.close() #7、關閉監聽套接字 tcpServerSocket.close()
運行流程
1、TCP伺服器
2、網路調試助手:
十、TCP客戶端代碼實現
所謂的伺服器端:就是提供服務的一方,而客戶端,就是需要被服務的一方
tcp的客戶端要比伺服器端簡單很多,如果說伺服器端是需要自己買手機、查手機卡、設置鈴聲、等待別人打電話流程的話,那麼客戶端就只需要找一個電話亭,拿起電話撥打即可,流程要少很多
#coding = utf-8 from socket import * #1、創建socket tcpClientSocket = socket(AF_INET,SOCK_STREAM) #2、鏈接伺服器 serverAddress = ("192.168.100.106",7788) tcpClientSocket.connect(serverAddress) #3、向伺服器發送數據 tcpClientSocket.send("哈哈".encode("gb2312")) #4、接收對方發送過來的數據,最大接收1024個位元組 receiveData = tcpClientSocket.recv(1024) print("接收到的數據為%s"%receiveData.decode("gb2312")) #5、關閉套接字 tcpClientSocket.close()
運行流程:
1、tcp客戶端
2、網路調試助手: