python網絡-Socket之TCP編程(26)

1、TCP簡介

一、TCP介紹數據庫

TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫爲 TCP)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。編程

TCP通訊須要通過建立鏈接、數據傳送、終止鏈接三個步驟。後端

TCP通訊模型中,在通訊開始以前,必定要先創建相關的連接,才能發送數據,相似於生活中,"打電話"。服務器

二、TCP面向鏈接網絡

通訊雙方必須先創建鏈接才能進行數據的傳輸,雙方都必須爲該鏈接分配必要的系統內核資源,以管理鏈接的狀態和鏈接上的傳輸。併發

雙方間的數據傳輸均可以經過這一個鏈接進行。socket

完成數據交換後,雙方必須斷開此鏈接,以釋放系統資源。tcp

這種鏈接是一對一的,所以TCP不適用於廣播的應用程序,基於廣播的應用程序請使用UDP協議。函數

三、TCP可靠傳輸網站

1)TCP採用發送應答機制

TCP發送的每一個報文段都必須獲得接收方的應答才認爲這個TCP報文段傳輸成功

2)超時重傳

發送端發出一個報文段以後就啓動定時器,若是在定時時間內沒有收到應答就從新發送這個報文段。TCP爲了保證不發生丟包,就給每一個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。而後接收端實體對已成功收到的包發回一個相應的確認(ACK);若是發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設爲已丟失將會被進行重傳。

3)錯誤校驗

TCP用一個校驗和函數來檢驗數據是否有錯誤;在發送和接收時都要計算校驗和。

4) 流量控制和阻塞管理

流量控制用來避免主機發送得過快而使接收方來不及徹底收下。

四、TCP與UDP的不一樣點

  • 面向鏈接(確認有建立三方交握,鏈接已建立才做傳輸。)
  • 有序數據傳輸
  • 重發丟失的數據包
  • 捨棄重複的數據包
  • 無差錯的數據傳輸
  • 阻塞/流量控制

 

2、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。

 

3、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狀態,開始進行數據傳輸。

 

4、TCP四次揮手

 

第一次揮手發送FIN請求,第一次揮手結束。

第二次揮手開始,被動方向主動方發送ACK確認碼,到這裏第二次揮手結束。

第三次握手開始被動方向主動方發送FIN號結束。

第四次揮手開始主動方向被動方發送ACK確認,等待2MSL後斷開TCP鏈接。

 

5、TCP的十種狀態

這十種狀態分別是三次握手和四次揮手中的狀態,在上面兩個圖中都給你們標記出來了,這裏再給你們一個簡單的圖表示

 

6、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時間結束再使用此端口。

 

7、TCP長鏈接和短鏈接

TCP在真正的讀寫操做以前,server與client之間必須創建一個鏈接,

當讀寫操做完成後,雙方再也不須要這個鏈接時它們能夠釋放這個鏈接,

鏈接的創建經過三次握手,釋放則須要四次握手,

因此說每一個鏈接的創建都是須要資源消耗和時間消耗的。

1. TCP短鏈接

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

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

在第 步驟5中,通常都是 client 先發起 close 操做。固然也不排除有特殊的狀況。從上面的描述看,短鏈接通常只會在 client/server 間傳遞一次讀寫操做!

2. TCP長鏈接

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

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

3. TCP長/短鏈接操做過程

(1)短鏈接的操做步驟是:創建鏈接——數據傳輸——關閉鏈接...創建鏈接——數據傳輸——關閉鏈接

(2) 長鏈接的操做步驟是:創建鏈接——數據傳輸...(保持鏈接)...數據傳輸——關閉鏈接

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

  • 長鏈接能夠省去較多的TCP創建和關閉的操做,減小浪費,節約時間。對於頻繁請求資源的客戶來講,較適用長鏈接。

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

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

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

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

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

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

 

8、TCP的通訊模型

tcp通訊模型中,在通訊開始以前,必定要先創建相關的連接,才能發送數據,相似於生活中,"打電話"

生活中的電話機,若是想讓別人能更夠打通我們的電話獲取相應服務的話,須要作一下幾件事情:

  1. 買個手機
  2. 插上手機卡
  3. 設計手機爲正常接聽狀態(即可以響鈴)
  4. 靜靜的等着別人撥打

tcp服務器如同上面的電話機過程同樣,在程序中,若是想要完成一個tcp服務器的功能,須要的流程以下:

  1. 建立一個socket套接字
  2. bind綁定ip和port
  3. listen使套接字變爲能夠被動連接
  4. accept等待客戶端的連接
  5. recv/send接收發送數據

 

9、TCP服務器代碼實現

#coding = utf-8
from socket import *
#一、建立socket套接字
tcpServerSocket = socket(AF_INET,SOCK_STREAM)
#二、綁定本地信息
address = ("",7788)
tcpServerSocket.bind(address)
#三、使用socket建立的套接字默認的屬性是主動的,使用listen將其變爲被動,這樣就能夠等着別人連接了
tcpServerSocket.listen(5)

"""
若是有新的客戶端來連接服務器,那麼就產生一個新的套接字專門爲這個客戶端服務器
newSocket用來爲這個客戶端服務
tcpServerSocket就能夠省下來專門等待其餘的客戶端的連接
"""
newSocket,clientAddress = tcpServerSocket.accept()

#四、接收對象發送過來的數據,最大接收1024個字節
reveiveData = newSocket.recv(1024)
print("接收的數據爲:%s"%reveiveData.decode())

#五、發送數據到客戶端
newSocket.send("haha".encode())

#六、關閉爲這個客戶端服務的套接字
newSocket.close()

#七、關閉監聽套接字
tcpServerSocket.close()

運行流程

一、TCP服務器

二、網絡調試助手:

 

10、TCP客戶端代碼實現

所謂的服務器端:就是提供服務的一方,而客戶端,就是須要被服務的一方

tcp的客戶端要比服務器端簡單不少,若是說服務器端是須要本身買手機、查手機卡、設置鈴聲、等待別人打電話流程的話,那麼客戶端就只須要找一個電話亭,拿起電話撥打便可,流程要少不少

#coding = utf-8
from socket import *

#一、建立socket
tcpClientSocket = socket(AF_INET,SOCK_STREAM)

#二、連接服務器
serverAddress = ("192.168.100.106",7788)
tcpClientSocket.connect(serverAddress)

#三、向服務器發送數據
tcpClientSocket.send("哈哈".encode("gb2312"))

#四、接收對方發送過來的數據,最大接收1024個字節
receiveData = tcpClientSocket.recv(1024)
print("接收到的數據爲%s"%receiveData.decode("gb2312"))

#五、關閉套接字
tcpClientSocket.close()

運行流程:

一、tcp客戶端

二、網絡調試助手:

相關文章
相關標籤/搜索