python-socket編程(一)原理篇

一、什麼是socket(套接字)

1.1 套接字的概述

Socket是應用層和網絡層的中間軟件抽象層,它是一組接口,由ip和端口組成。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。

數據交換就通過調用socket接口來進行交換。再由socket的程序來調用系統底層的數據交換。

其中socket包括基於文件類型的套接字家族(AF_UNIX),unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來獲取數據,兩個套接字進程運行在同一機器,可以通過訪問同一個文件系統完成通信

還有一種就是基於網絡類型的套接字(AF_INET)

1.2 套接字的工作流程

在這裏插入圖片描述

  • 1、首先在服務端創建一個socket套接字程序
  • 2、綁定ip和端口 bind()
  • 3、監聽此套接字端口 listen()
  • 4、等待和客戶端建立連接 accept()(三次揮手)
  • 5、接收數據 read()
  • 6、發送數據 write()
  • 7、關閉連接 close()(四次揮手)

二、tcp/ip協議

2.1 報文結構

在這裏插入圖片描述

2.2 基礎術語

  • 序列號seq:佔4個字節,用來標記數據段的順序,TCP把連接中發送的所有數據字節都編上一個序號,第一個字節的編號由本地隨機產生;給字節編上序號後,就給每一個報文段指派一個序號;序列號seq就是這個報文段中的第一個字節的數據編號
  • 確認號ack:佔4個字節,期待收到對方下一個報文段的第一個數據字節的序號;序列號表示報文段攜帶數據的第一個字節的編號;而確認號指的是期望接收到下一個字節的編號;因此當前報文段最後一個字節的編號+1即爲確認號
  • 確認ACK:佔1位,僅當ACK=1時,確認號字段纔有效。ACK=0時,確認號無效
  • 同步SYN:連接建立時用於同步序號。當SYN=1,ACK=0時表示:這是一個連接請求報文段。若同意連接,則在響應報文段中使得SYN=1,ACK=1。因此,SYN=1表示這是一個連接請求,或連接接受報文。SYN這個標誌位只有在TCP建產連接時纔會被置1,握手完成後SYN標誌位被置0
  • 終止FIN:用來釋放一個連接。FIN=1表示:此報文段的發送方的數據已經發送完畢,並要求釋放運輸連接

2.3 三次揮手

  • 發送端發送一個SYN=1,ACK=0;seq=x,標誌的數據包給接收端,請求進行連接,這是第一次握手;
  • 接收端收到請求並且允許連接的話,就會發送一個SYN=1,ACK=1;seq=y,ack=x+1標誌的數據包給發送端,告訴它,可以通訊了,並且讓發送端發送一個確認數據包,這是第二次握手;
  • 最後,發送端發送一個SYN=0,ACK=1,seq=x+1,ack=y+1的數據包給接收端,告訴它連接已被確認,這就是第三次握手
    在這裏插入圖片描述

2.3 四次揮手

  • 發送端發送FIN=1,ACK=0標誌的數據包給接收端,請求釋放連接
  • 接收端收到併發送ACK=1的標誌數據包給發送端,確認已經無數據要發送
  • 等待接收端的數據發送完畢後,接收端發送FIN=1的數據包給發送端
  • 發送端發送確認包ACK=1
  • 接收端收到後釋放鏈接,發送端等待2msl時間後關閉連接。
    在這裏插入圖片描述

三、tcp和udp的區別

  • tcp是面向鏈接的,udp是面向非鏈接的:tcp需要建立三次握手,而udp不需要,
  • tcp是可靠傳輸,udp是非可靠傳輸:tcp發送的數據流,兩次發送之間沒有邊界,可傳輸大量數據;而udp發送的數據報,兩次發送之間有明確邊界,每一次傳送過得數據量有限
  • tcp開銷大,udp開銷小:tcp每次傳送都需要建立鏈接,因此開銷大,速度慢

四、linux系統tcp參數的調優

  • vi /etc/systcl.conf 添加一下內容
net.ipv4.tcp_syncookies = 1
#表示開啓SYNcookies,當出現SYN隊列溢出的時候,啓用cookies來處理,可防範少量SYN攻擊
net.ipv4.tcp_tw_reuse = 1
#開啓tcp重用,允許將TIME—WAIT套接字重新用於新的TCP連接
net.ipv4.tcp_tw_recycle = 1
#開啓TCP連接中的TIME-WAIT套接字的快速回收
net.ipv4.tcp_fin_timeout = 30
#修改tcpfin的默認timeout時間
  • /bin/sysctl -p 讓參數生效

面試常見問題

1、爲什麼連接的時候是三次握手,關閉的時候卻是四次握手?
答:因爲當Server端收到Client端的SYN連接請求報文後,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,“你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

2、爲什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態
答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在Client發送出最後的ACK回覆,但該ACK可能丟失。Server如果沒有收到ACK,將不斷重複發送FIN片段。所以Client不能立即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK之後進入到TIME_WAIT狀態。Client會設置一個計時器,等待2MSL的時間。如果在該時間內再次收到FIN,那麼Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片段在網絡中最大的存活時間,2MSL就是一個發送和一個回覆所需的最大時間。如果直到2MSL,Client都沒有再次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP連接。

3、爲什麼不能用兩次握手進行連接?
若把三次握手改成僅需要兩次握手,死鎖是可能發生的。作爲例子,考慮計算機S和C之間的通信,假定C給S發送一個連接請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認爲連接已經成功地建立了,可以開始發送數據分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S 是否已準備好,不知道S建立什麼樣的序列號,C甚至懷疑S是否收到自己的連接請求分組。在這種情況下,C認爲連接還未建立成功,將忽略S發來的任何數據分 組,只等待連接確認應答分組。而S在發出的分組超時後,重複發送同樣的分組。這樣就形成了死鎖。

4、如果已經建立了連接,但是客戶端突然出現故障了怎麼辦?
TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設置爲2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉連接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章