章節回顧:
《TCP/IP詳解卷1:協議》第3章 IP:網際協議(1)-讀書筆記
《TCP/IP詳解卷1:協議》第3章 IP:網際協議(2)-讀書筆記
《TCP/IP詳解卷1:協議》第4章 ARP:地址解析協議-讀書筆記
《TCP/IP詳解卷1:協議》第5章 RARP:逆地址解析協議-讀書筆記
《TCP/IP詳解卷1:協議》第6章 ICMP:Internet控制報文協議-讀書筆記
《TCP/IP詳解卷1:協議》第11章 UDP:用戶數據報協議-讀書筆記
《TCP/IP詳解卷1:協議》第17、18章 TCP:傳輸控制協議(1)-讀書筆記
《TCP/IP詳解卷1:協議》第17、18章 TCP:傳輸控制協議(2)-讀書筆記
《TCP/IP詳解卷1:協議》第19章 TCP的交互數據流-讀書筆記
3、連接建立的超時
有很多情況導致無法建立連接。一種情況是服務器主機沒有處於正常狀態。
4、最大報文段長度
最大報文段長度(MSS)表示TCP傳往另一端的最大塊數據的長度。當一個連接建立時,連接的雙方都要通告各自的MSS。
當建立一個連接時,每一方都有用於通告它期望接收的MSS選項(MSS選項只能出現在SYN報文段中)。如果一方不接收來自另一方的MSS值,則MSS就定為默認值536字節(這個默認值允許20字節的IP首部和20字節的TCP首部以適合576字節IP數據報)。
注意:
(1)一般說來,如果沒有分段發生,MSS越大越好。報文段越大允許每個報文段傳送的數據就越多,相對IP和TCP首部有更高的網絡利用率。
(2)當TCP發送一個SYN時,或者是因為一個本地應用進程想發起一個連接,或者是因為另一端的主機收到了一個連接請求,它能將MSS值設置為外出接口上的MTU長度減去固定的IP首部和TCP首部長度。
(3)如果目的IP地址為“非本地的(non-local)”,MSS通常的默認值為536。
說明:區分地址是本地還是非本地的方法是:如果目的IP地址的網絡號與子網號都與本機相同,則是本地的;如果目的IP地址的網絡號與本機相同而子網號不同,則可能是本地的,也可能是非本地的。
(4)MSS使得主機限制另一端發送數據報的長度。加上主機也能控制它發送數據報的長度,這使得以較小MTU連接到一個網絡上的主機避免分段。
下面舉個書中的例子(比較懶,沒有搭建環境)
主機sun向slip發起一個TCP連接,利用tcpdump命令來觀察報文段:
說明:
(1)sun發送的報文段不能超過256字節的數據,因為slip已經告知它的MSS值為256。(上圖第二個紅框)
(2)slip知道它外出接口的MTU長度為296,所以即使sun已經告訴它的MSS為1460(上圖第一個紅框),但為避免將數據分段,它不會發送超過256字節數據的報文段。
(3)如果兩端主機都連接到以太網上,都采用536的MSS,但中間網絡采用296的MTU,同樣會出現分段。
5、TCP的半關閉
TCP提供了連接的一端在結束它的發送后還能接收來自另一端數據的能力,即半關閉。
注意:很少有應用程序使用它,如果想要使用這個功能,需要編程接口提供一個方式來說明。
下面給出一個例子:
意思是這樣的:客戶結束了發送數據(發送了FIN),服務器發送ACK表示確認后,仍然可以發送數據給客戶(圖中紅框)。
6、TCP的狀態變遷圖
下面這張圖我沒有仔細研究,它應該包含了有關發起和終止TCP連接的所有規則。
(1)2MSL等待狀態
TIME_WAIT狀態也稱為2MSL等待狀態。每個具體TCP實現必須選擇一個報文段最大生存時間MSL(Maximum Segment Lifetime)。它是任何報文段被丟棄前在網絡內的最長時間。
注意:MSL是個有限的時間,我們知道TCP報文段以IP數據報在網絡中傳輸,IP數據報是由TTL字段限制其生存時間的。RFC 793指出MSL為2分鍾。實現中的常用值是30秒,1分鍾,或2分鍾。
對於給定的MSL值,原則是:當TCP執行一個主動關閉,並發回最后一個ACK,該連接必須在TIME_WAIT狀態停留的時間為2倍的MSL。這樣可讓TCP再次發送最后的ACK以防這個ACK丟失(另一端超時並重發最后的FIN)。
說明:
1)客戶執行主動關閉並進入TIME_WAIT是正常的。服務器通常執行被動關閉,不會進入TIME_WAIT狀態。
2)TCP連接在2MSL等待期間,這個連接的socket(客戶的IP地址和端口號,服務器的IP地址和端口號)不能再被使用。這個連接只能在2MSL結束后才能再被使用。
(2)平靜時間的概念
如果處於2MSL等待端口的主機出現故障,它會在MSL秒內重新啟動,並立即使用故障前處於2MSL的socket來建立一個新的連接。在故障前從這個連接發出而遲到的報文段會被錯誤地當作屬於重啟后新連接的報文段。
為了防止這種情況,RFC 793指出TCP在重啟動后的MSL秒內不能建立任何連接,稱為平靜時間(quiet time)。
(3)FIN_WAIT_2狀態
如上面的圖所示:FIN_WAIT_2狀態時,客戶已經發出了FIN,另一端也已對它進行確認。
除非客戶設置了半關閉,否則將等待另一端的應用層意識到它已收到一個文件結束符說明,並向我們發一個FIN 來關閉連接。只有這樣,我們這端才會從FIN_WAIT_2狀態進入TIME_WAIT狀態。
7、復位報文段
TCP首部中的RST比特是用於“復位”的,一般無論何時一個報文段發往“基准連接”出現錯誤,TCP都會發出一個復位報文段。
說明:“基准連接”是指由目的IP地址和端口號以及源IP地址和端口號指明的連接。
(1)到不存在的端口的連接請求
產生復位的一種常見情況是當連接請求到達時,目的端口沒有進程正在聽。
注意:對於UDP,當一個數據報到達目的端口時,該端口沒在使用,它將產生一個ICMP端口不可達的信息;對於TCP,則使用復位。
圖中的意思是說:主機bsdi向svr4的20000端口發送SYN,然后svr4告訴bsdi一個復位連接的信息。
(2)異常終止一個連接
終止一個連接的正常方式是一方發送FIN。這也稱為有序釋放,因為在所有排隊數據都已發送之后才發送FIN,正常情況下沒有任何數據丟失。但也有可能發送一個復位報文段而不是FIN來中途釋放一個連接。這也稱為為異常釋放。
異常終止一個連接對應用程序來說有兩個優點:
1)丟棄任何待發數據並立即發送復位報文段;
2)RST的接收方會區分另一端執行的是異常關閉還是正常關閉。
特別注意:RST報文段不會導致另一端產生任何響應,另一端根本不進行確認。收到RST的一方將終止該連接,並通知應用層連接復位。
(3)檢測半打開連接
如果一方已經關閉或異常終止連接而另一方卻還不知道,將這樣的TCP連接稱為半打開的。
說明:
1)任何一端的主機異常都可能導致半打開連接。只要不在半打開連接上傳輸數據,仍處於連接狀態的一方就不會檢測到另一方已經出現異常。
2)半打開連接的另一個常見原因是當客戶主機突然掉電而不是正常的結束客戶應用程序后再關機。
8、同時打開
兩個應用程序同時彼此執行主動打開的情況是可能的,盡管發生的可能性極小。每一方必須發送一個SYN,且這些SYN必須傳遞給對方。這需要每一方使用一個對方熟知的端口作為本地端口,稱為同時打開。
TCP對於同時打開僅建立一條連接而不是兩條連接。當出現同時打開時:
兩端幾乎同時發送SYN,並進入SYN_SENT狀態。當每一端收到SYN時,狀態變為SYN_RCVD,同時它們都再發SYN並對收到的SYN進行確認。當雙方都收到SYN及相應的ACK時,狀態都變遷為ESTABLISHED。
注意:
(1)一個同時打開的連接需要交換4個報文段,比正常的三次握手多一個。
(2)對於同時打開的連接,我們沒有將任何一端稱為客戶或服務器,因為每一端既是客戶又是服務器。
9、同時關閉
雙方都執行主動關閉也是可能的,TCP也允許同時關閉。
同時關閉過程為:
(1)當應用層發出關閉命令時,兩端均從ESTABLISHED變為FIN_WAIT_1。這將導致雙方各發送一個FIN,兩個FIN經過網絡傳送后分別到達另一端。
(2)收到FIN后,狀態由FIN_WAIT_1變為CLOSING,並發送最后的ACK。
(3)當收到最后的ACK時,狀態變化為TIME_WAIT。
注意:同時關閉和正常關閉報文段交換數目相同。
10、TCP選項
TCP首部可以包含選項部分。
選項說明:
(1)每個選項的開始是1字節kind字段,說明選項的類型。
(2)kind字段為0和1的選項僅占1個字節。其他選項在kind字節后還有len字節,它說明的長度是指總長度,包括kind字節和len字節。
(3)設置無操作選項的原因在於允許發方填充字段為4字節的倍數。
11、TCP 服務器的設計
大多數TCP服務器進程是並發的。當一個新的連接請求到達服務器時,服務器接受這個請求,並調用一個新進程來處理這個新的客戶請求。
(1)TCP服務器端口號
當不同進程連接到服務器時,服務器端口號都是一樣的。
(2)限定的本地IP地址
限制本地的IP地址后,不同鏈路的連接請求可能被TCP內核拒絕。
(3)限制遠端IP地址
服務器必須不指明遠端socket,而等待連接請求的到來,然后檢查客戶端的IP地址和端口號。
圖18-22(這張圖我還沒有看懂)總結了TCP服務器進行連接時三種類型的地址綁定。在三種情況中,lport是服務器的熟知端口,local IP必須是一個本地接口的IP地址。
(4)呼入連接請求隊列
一個並發服務器調用一個新的進程來處理每個客戶請求,因此處於被動連接請求的服務器應該始終准備處理下一個呼入的連接請求。但仍有可能出現當服務器在創建一個新的進程時,或操作系統正忙於處理優先級更高的進程時,到達多個連接請求。
在伯克利的TCP實現中采用以下規則:
1)正等待連接請求的一端有一個固定長度的連接隊列,該隊列中的連接已被TCP接受(即三次握手已經完成),但還沒有被應用層所接受。
注意:TCP接受一個連接是將其放入這個隊列,而應用層接受連接是將其從該隊列中移出。
2)應用層將指明該隊列的最大長度,這個值通常稱為積壓值(backlog)。它的取值范圍是0~5之間的整數,包括0和5(大多數的應用程序都將這個值指明為5)。
3)當一個連接請求(SYN)到達時,TCP使用一個算法,根據當前連接隊列中的連接數來確定是否接收這個連接。
4)如果對於新的連接請求,該TCP監聽的端點的連接隊列中還有空間,TCP模塊將對SYN進行確認並完成連接的建立。
注意:
(i)應用層只有在三次握手中的第三個報文段收到后才會知道這個新連接。
(ii)當客戶進程主動打開成功但服務器的應用層還不知道這個新的連接時,它可能會認為服務器進程已經准備好接收數據了。如果這樣,服務器的TCP僅將接收的數據放入緩沖隊列。
5)如果對於新的連接請求,連接隊列中已沒有空間,TCP將不理會收到的SYN,也不發回任何報文段(即不發回RST)。如果應用層不能及時接受已被TCP接受的連接,這些連接可能占滿整個連接隊列,客戶的主動打開最終將超時。