18.TCP鏈接的創建與終止

鏈接的創建與終止

經過以下命令讓主機svr4與bsdi發起並終止鏈接服務器

image_1ciuvborm19vt1c6m1bhb1i8vmt99.png-29.3kB

下面爲tcpdump輸出的TCP報文段部分socket

image_1ciuvdlpa1g981ruv11r2104813tem.png-147.2kB

每行格式爲源>目的:標誌tcp

上圖中的標誌的解釋大數據

image_1ciuvj3se1b7m1qvrvet1gv16ds13.png-82.5kB

  • 第1行,1415531521:1415531521(0)表示分組的開始序號爲1415531521,結束序號也爲1415531521,數據字節數爲0。這是鏈接同步請求,沒有任何數據交換
  • 第2行,ack 1415531522表明確認序號,這個值只有在ACK標誌位爲1時才顯示
  • win 4096表示發送端通告的窗口大小
  • < mss 1024 >表示發送端指明的最大報文長度,發端不接收超過該長度的報文段

創建鏈接協議

image_1civ1rl5k11e9150i1c4a1g081p001g.png-152.4kB

三次握手:線程

  1. 客戶端發送一個SYN段做爲鏈接請求,初始化序號爲1415531521
  2. 服務端響應一個SYN段,初始化序號爲1823083521。同時發送確認報文,確認序號爲1415531521+1=1415531522。一個SYN佔用一個序號
  3. 客戶端響應確認報文,確認序號爲1823083521+1=1823083522

終止鏈接協議

一個TCP鏈接是全雙工,數據在兩個方向傳遞,所以若是要關閉TCP鏈接,必須單獨關閉兩個方向的鏈接設計

四次握手:3d

image_1civ9i8ha1nq132p1odatjh2531t.png-67kB

  1. 客戶端發送FIN,請求關閉鏈接
  2. 服務端收到FIN後,響應ACK
  3. 服務端發送FIN,請求關閉鏈接
  4. 客戶端收到FIN後,響應ACK

之因此比鏈接多一次握手,是由於TCP支持半關閉,容許一邊關閉鏈接後另外一邊仍能發送數據,因此沒法合併報文5和報文6,二者之間仍然可能存在單向數據傳輸的報文。因此一旦使用了半關閉,這四次握手就會分紅兩個階段執行code

創建鏈接超時

image_1cj0943mo1t991m4v61ij8k1otd2a.png-165.2kB

其中第一、2次請求間隔5.8秒,第二、3次請求間隔24秒,其中tos 0x10表明telnet將IP數據報服務類型字段設爲最小時延orm

image_1cj0e26n51svo1vkh14eq13dl12f62n.png-81.6kB

上面顯示的總耗時76秒,是由於在大多數實現中,新建鏈接的時間最長爲75秒server

BSD TCP採用500ms定時器,在初始化設置時,第一個500ms內會在任意時刻滴答一下,致使第一個間隔不是6秒而是5.8秒,但第二個間隔倒是準確的24秒

image_1cj0ecv2o1km66if8fe1tfe40734.png-123.5kB

最大報文段長度

MSS,表示TCP傳往另外一端最大數據塊的長度。當創建TCP鏈接時,雙方都要通告各自的MSS。如當A告知B MSS爲1460時,表示B能夠發給A的最大數據塊長度就是1460

一般以太網將MSS設爲MTU大小減去IP首部和TCP首部長度,即1500-20-20=1460

TCP的半關閉

TCP提供了發送端在結束髮送後,依然能夠接收數據的能力,這就是半關閉

在應用程序調用shutdown,而且第二個參數爲1時,會使用半關閉。普通的close不會有半關閉。因此不多應用程序會使用到半關閉

爲何要有半關閉?

image_1cj0lsfdthsnhlacpc62p1mih9.png-162.3kB

場景:當發送遠程命令到目的主機執行時,命令發送完後,client就能結束數據發送,但仍然接收目的主機發回的執行結果,這就是半關閉狀態,當目的主機發完數據時,結束數據發送,完成鏈接關閉。沒有半關閉,目的主機沒法知道client數據何時發完,也就沒法執行命令並響應結果

TCP狀態變遷圖

image_1cj0m8gfv1pd89b81geukgs9aum.png-518.5kB

其中SYN收到就是SYN_RCVD

image_1cj0nsuqiirt1k2v1ng31dob1ped1g.png-185.3kB

經過上面兩個圖能夠觀察到

  • client從CLOSED到ESTABLISHED所須要發送和接收的報文
  • server從LISTEN到ESTABLISHED所須要發送和接收的報文
  • ESTABLISHED狀態才能進行數據傳輸
  • client從ESTABLISHED到CLOSED所須要發送和接收的報文
  • server從ESTABLISHED到CLOSED再到LISTEN所須要發送和接收的報文

並不存在CLOSED這個狀態,它是一個假象的狀態起點和終點,因此server從CLOSED過分到LISTEN不須要特殊處理

TIME_WAIT狀態

又稱2MSL等待狀態,即2倍的報文段最大生存週期

當TCP主動關閉一方發送最後一個ACK時,會進入TIME_WAIT狀態,等待2MSL時間才能完全關閉鏈接

爲何須要等待2MSL呢?

  1. 防止最後一個ACK丟失。若是真丟失,被動關閉一方會重發FIN(2MSL=MSL(丟失的ACK)+MSL(重發的FIN)
  2. 在2MSL期間不能複用鏈接(源IP、目的IP、源端口、目的端口的四元祖),避免原始鏈接中迷途的數據跑到新鏈接中

大部分TCP實現較爲嚴格,在TIME_WAIT期間,沒法複用端口

  • 若是客戶端主動關閉鏈接,進入TIME_WAIT,因爲客戶端是隨機端口,沒法複用原來端口能夠很容易作到
  • 若是服務端主動關閉鏈接,進入TIME_WAIT,因爲服務端是知名端口,沒法複用原來端口會致使重啓服務耗時至少爲2MSL。不少實現提供SO_REUSEADDR來繞過這個限制,保證服務端能夠複用TIME_WAIT期間的端口

FIN_WAIT_2狀態

當主動關閉一方發送FIN,並收到ACK後,會進入FIN_WAIT_2狀態,直到被動關閉一方發送FIN,主動方纔會響應ACK並進入TIME_WAIT狀態

因此,若是被動關閉一方不關閉鏈接,會致使主動關閉一方永遠處於FIN_WAIT_2狀態,而被動關閉一方永遠處於CLOSE_WAIT狀態

復位報文段

當報文段發往一個socket時出現錯誤,TCP就會發出一個復位報文段。一般有如下三種場景:

  1. 到不存在的端口發起鏈接請求。當發送到目的端,發現端口不存在,UDP會響應一個ICMP端口不可達差錯,TCP會響應復位報文段
  2. 異常終止一個鏈接。經過FIN正常關閉,可是須要處理排隊的數據;復位報文段異常關閉,能夠當即丟棄排隊的數據
  3. 檢測半打開鏈接。當一邊異常關閉鏈接而另外一邊不知道,這種是半打開鏈接。如server異常斷電重啓,client不知server的情況,繼續發送報文,server收到後立馬響應一個復位報文段

TCP選項

image_1cj94hccc4vb1r2m5je1u281as8p.png-89.3kB

如圖顯示了三個選項:

  1. 最大報文段長度
  2. 窗口擴大因子
  3. 時間戳

實際爲了保證選項總長度是4字節的倍數,須要在其中填充無操做NOP選項

image_1cj94lvah1gjrf8lck71c6g1pq526.png-15.9kB

TCP服務器的設計

  • 當服務端監聽鏈接時,會處於LISTEN狀態
  • 當客戶端請求到來時,會啓動一個線程/進程去接收客戶端鏈接請求
  • 當客戶端服務端鏈接創建時,處於ESTABLISHED狀態

image_1cjfq6vjkc5otqo1at41vtqcsi19.png-50.8kB

服務器能夠限定本地監聽的IP地址和遠端請求的IP地址

鏈接隊列

當服務器忙於處理客戶端請求時,多的請求在鏈接創建後會放入鏈接隊列。鏈接隊列有如下規則:

  1. 監聽鏈接請求的一端會有固定長度的鏈接隊列,該隊列存儲已創建鏈接(完成了三次握手)的請求,稍後應用程序會從該隊列中移除請求並處理
  2. 積壓值(backlog)是這個隊列的最大長度
  3. 當該隊列已滿,TCP不會將理會後續的鏈接請求(SYN),而且不會回覆RST。RST表明這個請求是硬錯誤,不能重試。而不理會會讓客戶端請求超時,發現是一個軟錯誤,會進行重試
相關文章
相關標籤/搜索