【TCP/IP详解 卷一:协议】第十八章 TCP连接 的建立与终止 (2)其余内容
18.5 TCP的半關(guān)閉
牢記 TCP 是 全雙工 的。
半關(guān)閉:TCP提供了連接的一端 在結(jié)束了它的發(fā)送后 還能接收來自另外一端數(shù)據(jù)的能力。但是只有很少的應(yīng)用程序利用它。
為了實現(xiàn)這個特性,編程接口必須提供一種方法來說明“我已經(jīng)完成了數(shù)據(jù)的傳送,并且發(fā)了FIN給另外一端,但是我還是想接收另外一端發(fā)送來的數(shù)據(jù),直到結(jié)束(向我發(fā)送FIN)”。
在 執(zhí)行半關(guān)閉 的一端 收到來自另外一端的 FIN 之后,傳送一個EOF給應(yīng)用程序,并對這個 FIN 進(jìn)行確認(rèn)并發(fā)送ACK,結(jié)束了這個連接。
18.6 重點:TCP的狀態(tài)變遷圖
參考:TCP的狀態(tài)變遷圖
狀態(tài):描述
CLOSED:無連接是活動的或正在進(jìn)行
LISTEN:服務(wù)器在等待進(jìn)入呼叫
SYN_RECV:一個連接請求已經(jīng)到達(dá),等待確認(rèn) 被動打開
SYN_SENT:應(yīng)用已經(jīng)開始,打開一個連接 主動打開
ESTABLISHED:正常數(shù)據(jù)傳輸狀態(tài)
FIN_WAIT1:應(yīng)用說它已經(jīng)完成
FIN_WAIT2:另一邊已同意釋放
ITMED_WAIT:等待所有分組死掉
CLOSING:兩邊同時嘗試關(guān)閉
TIME_WAIT:另一邊已初始化一個釋放
LAST_ACK:等待所有分組死掉
注意:第一點,我們使用粗的實線箭頭表示正常的客戶端狀態(tài)變遷,使用虛線箭頭表示正常的服務(wù)器狀態(tài)變遷。
第二點是兩個導(dǎo)致進(jìn)入 ESTABLISHED 狀態(tài)的變遷 對應(yīng)打開一個連接(SYN_SENT & SYN_RCVD/SYN_RECV),和兩個導(dǎo)致ESTABLISHED狀態(tài)離開的變遷 對應(yīng)關(guān)閉一個連接(FIN_WAIT1 & FIN_WAIT2)。
主動打開:SYN_SENT 被動打開:SYN_RECV
主動關(guān)閉:FIN_WAIT1 FIN_WAIT2 TIME_WAIT CLOSING
被動關(guān)閉:CLOSE_WAIT LAST_ACK
課程通過 TCP時序圖來說明
我們執(zhí)行被動關(guān)閉(進(jìn)入LISTEN),收到一個SYN,發(fā)送一個帶ACK的SYN(進(jìn)入SYN_RCVD),然后收到一個RST,而不是一個ACK,便又回到LISTEN狀態(tài)并等待另外一個連接請求的到來。
左邊的客戶執(zhí)行主動打開,而右邊的服務(wù)器執(zhí)行被動打開。圖中顯示客戶端執(zhí)行主動關(guān)閉,但是正如我們之前提到的,另外一端也可以執(zhí)行主動關(guān)閉。
18.6.1 2MSL等待時間
TIME_WAIT狀態(tài)也稱為2MSL等待狀態(tài)。
MSL:TCP實現(xiàn)選擇的 一個報文段最大生存時間MSL。與IP的TTL類似。
對IP數(shù)據(jù)報TTL的限制是 基于跳數(shù),而不是 定時器。
當(dāng)TCP執(zhí)行一個主動關(guān)閉 并且 發(fā)送最后一個ACK(由主動關(guān)閉端發(fā)送),該連接在 TIME_WAIT狀態(tài) 停留的時間為2倍的MSL。這樣如果最后的ACK丟失 -> 另外一端(被動關(guān)閉)超時 重新發(fā)送FIN -> 可以讓TCP重發(fā)最后一個ACK。
在連接處于2MSL狀態(tài)的時候,任何遲到的報文段都將被丟棄。因為處在2MSL狀態(tài)等待的,由socket pair(目的IP地址,源IP地址,目的端口號,源端口號)定義的連接在這段時間內(nèi)不能再次使用。
一個連接由socket pair定義,一個連接的新的實例(instance)稱為該連接的替身。
前文有提到,當(dāng)要建立一個有效的連接的時候,來自該連接的 一個較早替身 的遲到報文段(SYN/ACK...) 為了防止它作為 使用相同socket pair的新連接 的一部分 將會被曲解。
大概意思是:來自舊連接的 遲到的報文段,為了防止被當(dāng)成 新連接(采用相同socket pair)的一部分,會被銷毀。舊的東西不能被當(dāng)成新的東西,應(yīng)該銷毀。
如果我們一直重啟服務(wù)器程序,并測量它到成功的時間,我們就可以確定2MSL值。
18.6.2 平靜時間
對于來自 某個連接的較早替身 的遲到報文段,2MSL等待可以 防止將它解釋成 使用相同接口對(socket pair)的新連接 的一部分(就是防止解釋成另外一個連接的部分)。
平靜時間:TCP在重新啟動的MSL秒內(nèi)不能建立任何連接。
防止的是:處于2MSL等待狀態(tài)的主機重新啟動,如果使用 處于2MSL的socket pair(確定一個連接) 來建立一個新的連接,那么任何 之前遲到的(舊連接的)報文段 都會被錯誤的當(dāng)成新連接的一部分。
18.6.3 FIN_WAIT_2狀態(tài)
FIN_WAIT_2: 在主動關(guān)閉端 發(fā)送了第一個FIN 并且 接收到了ACK 之后,進(jìn)入FIN_WAIT_2狀態(tài)。
只有當(dāng):另外一端的應(yīng)用層 意識到它已經(jīng)接收了一個文件結(jié)束符(EOF),并且向我們發(fā)送 第二個FIN 來關(guān)閉另外一個方向的連接時,在主動關(guān)閉端接收到第二個FIN之后,我們才會從FIN_WAIT_2狀態(tài) 轉(zhuǎn)換到 TIME_WAIT狀態(tài)。
18.7 復(fù)位報文段
TCP首部的 RST比特 是用于復(fù)位的。無論什么時候,發(fā)送往 基準(zhǔn)的連接(即由socket pair確定的連接) 的報文段 出現(xiàn)錯誤,TCP都會發(fā)出一個復(fù)位報文段。
有以下三種情況:
- 對方端口不存在
- 異常關(guān)閉
- 檢查半打開連接
18.7.1 對方端口不存在
當(dāng)連接請求到達(dá)時,目的端口沒有進(jìn)程正在LISTEN。這個時候,對于UDP:產(chǎn)生一個ICMP端口不可達(dá)報文。對于TCP:使用復(fù)位。
18.7.2 異常關(guān)閉
終止一個連接的正常方法是:發(fā)送FIN,進(jìn)行四次揮手。稱為 有序釋放。
但是也有可能發(fā)送一個復(fù)位數(shù)據(jù)報而不是FIN來 中途釋放一個連接。稱為 異常釋放。
異常終止一個連接 對應(yīng)用程序的兩個優(yōu)點:
- 丟棄任何待發(fā)數(shù)據(jù)報并立刻發(fā)送復(fù)位報文段。
- RST的接收方會 區(qū)別 另外一端執(zhí)行的是 異常關(guān)閉 還是 正常關(guān)閉,應(yīng)用程序使用的API 必須 提供 產(chǎn)生異常關(guān)閉 而不是正常關(guān)閉 的手段。
需要注意的是:RST報文段 不會導(dǎo)致另外一端產(chǎn)生任何響應(yīng),另外一端根本不進(jìn)行確認(rèn),收到RST的一端將終止該連接,并通知應(yīng)用層連接進(jìn)行復(fù)位。
19.7.3 檢查半打開連接
半打開:一方已經(jīng)關(guān)閉或者異常終止連接,而另外一方仍然不知道,這樣的TCP連接稱作 半打開。
常見原因:客戶主機突然掉電。
我們異常關(guān)閉服務(wù)器,然后重新啟動,讓客戶端向服務(wù)器發(fā)送數(shù)據(jù)(斷電之前有連接),由于服務(wù)器的TCP已經(jīng)重新啟動,它將丟失 復(fù)位 之前連接的所有信息,因此它不知道客戶端新發(fā)送的數(shù)據(jù)報中 提到的連接。
這個時候,TCP的處理是:接收方以復(fù)位作為應(yīng)答。
18.8 同時打開
每一方必須發(fā)送一個SYN,并且這些SYN必須傳遞給對方。這需要每一方使用一個對方熟知的端口 作為本地端口。稱為同時打開。
比如 主機A中 一個應(yīng)用程序使用 7777本地端口,與主機B的端口8888 執(zhí)行主動打開。B中的應(yīng)用程序使用 8888本地端口,并與A中的端口7777 執(zhí)行主動打開。
每一端 既是服務(wù)器 又是客戶端。
tcp協(xié)議在遇到這種情況時,只會打開一條連接。(其他,比如OSI七層模型中的傳輸層 使用的是兩條連接)
這個連接的建立過程需要4次數(shù)據(jù)交換,而一個典型的連接建立只需要3次交換(即3次握手)。
18.9 同時關(guān)閉
雙方都執(zhí)行主動關(guān)閉,同時關(guān)閉和正常關(guān)閉使用的 段交換數(shù)目 相同。
18.11 TCP服務(wù)器的設(shè)計
回顧 UDP服務(wù)器的設(shè)計,大多數(shù)UDP服務(wù)器是 重復(fù)型 的,這意味著 單個服務(wù)器的進(jìn)程 對 單個UDP端口上 的所有客戶請求進(jìn)行處理。每一個UDP端口都與一個有限大小的輸入隊列相聯(lián)系。
大多數(shù)TCP服務(wù)器是 并發(fā)的。當(dāng)一個新的連接請求到達(dá)服務(wù)器的時候,服務(wù)器接受這個請求,并調(diào)用一個新進(jìn)程 來處理這個新的客戶請求,不同的操作系統(tǒng)使用不同的技術(shù)來調(diào)用新的服務(wù)器進(jìn)程。也可以使用輕型進(jìn)程 -線程(thread)。
18.11.1 TCP服務(wù)器端口
解決問題:TCP如何處理端口號?
不同的連接請求,有可能使用相同的服務(wù)器端口號,但是需要我們注意的一點是(或者說 應(yīng)該牢記的是):TCP通過socket pair來確定一條連接。也就是說,TCP通過本地IP地址,源IP地址,本地端口號,源端口號 “四人幫”來處理多個連接請求。
18.11.2 & 18.11.3 限定的本地IP地址 & 限定的源端IP地址
介紹了 服務(wù)器必須使用 特定的本地IP地址 和 服務(wù)器指定遠(yuǎn)端IP地址和遠(yuǎn)端端口號 的情況。
18.11.4 呼入連接請求隊列
一個并發(fā)型服務(wù)器 調(diào)用一個新的進(jìn)程 來處理客戶的連接請求,因此 處于被動連接請求 的服務(wù)器應(yīng)該始終準(zhǔn)備處理下一個 呼入的連接請求。
解決問題:服務(wù)器正忙的時候,如何處理新的請求?
(1)在等待連接的一端(服務(wù)器端)有一個固定長度的連接隊列,該隊列中的連接已經(jīng)被TCP接受(完成三次握手),但是還沒有被應(yīng)用程序接受。
(2)積壓值:應(yīng)用層指明的 隊列最長長度。取值范圍:0-5
(3)我們期望:積壓值 = 這一端點所能接受的最多連接。但是事實是 并不相等。
(4)隊列還有空間的時候,TCP確認(rèn)完之后,把新的請求放入隊列中。
(5)隊列沒有空間了,TCP不理會新的連接請求,也不發(fā)會 RST。最終 客戶端的主動打開會超時。
注意點:
- 什么時候進(jìn)隊列?-答:TCP確認(rèn)完畢之后,即三次握手完成。
- 什么時候出隊列?-答:應(yīng)用層知道了這個連接,并接收了它。
- 什么是積壓值?-答:隊列最長長度,所能容納的最多連接請求數(shù)。
2016/8/13
總結(jié)
以上是生活随笔為你收集整理的【TCP/IP详解 卷一:协议】第十八章 TCP连接 的建立与终止 (2)其余内容的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux图机界面机制
- 下一篇: 写一个脚本,判断下如果是阴历7月7日,在