TCP/IP協議的學習筆記
1.OSI和TCP/IP的協議體系結構
OSI是開放系統互連參考模型,它的七層體系結構概念清楚,理論也比較完整,但它既復雜又不實用。而TCP/IP是一個四層的體系結構,它包含應用層、傳輸層、網際層和網絡接口層。TCP/IP體系結構雖然 簡單,但它卻得到了廣泛的應用。OSI失敗的原因歸納為:
(1)OSI的專家缺乏實際經驗,他們在完成OSI標準時沒有商業驅動力;
(2)OSI的協議實現過分復雜,而且運行效率很低;
(3)OSI標準的制定周期太長,因而使得按OSI標準生產的設備無法及時進入市場;
(4)OSI的層次劃分不太合理,有些功能多個層次中重復使用
2.TCP:傳輸控制協議,一個位於傳輸層的協議
傳輸層的協議主要是UDP和TCP,UDP協議比較簡單,所以沒有過多的區了解,僅知道UDP是面向無連接的,不可靠傳輸,傳輸數據小,但是速度快。TCP協議是面向連接的,可靠穩定。TCP在傳送數據之前,會有三次握手建立連接;傳遞數據時,有確認、窗口、重傳、擁塞控制機制;在傳輸數據後,還會斷開連接,來釋放系統資源。但是正是因為這樣也存在很多缺點,效率低,占用系統資源高,也容易被人攻擊。UDP、TCP的主要區別,參考 https://www.cnblogs.com/xiaomayizoe/p/5258754.html
(1)TCP報文結構分析
(2)TCP三次握手建立連接
(1)第一次握手:建立連接時,客戶端
(2)第二次握手:服務器B收到SYN包,必須確認客戶A的SYN(ACK=j+1),同時自己也發送一個SYN包(SYN=k),即SYN+ACK包,此時服務器B進入SYN_RECV狀態。
(3)第三次握手:客戶端A收到服務器B的SYN+ACK包,向服務器B發送確認包ACK(ACK=k+1),此包發送完畢,客戶端A和服務器B進入ESTABLISHED狀態,完成三次握手。
完成三次握手,客戶端與服務器開始傳送數據。
(3)TCP四次揮手斷開連接
(1)客戶端A發送一個FIN,用來關閉客戶A到服務器B的數據傳送。
(2)服務器B收到這個FIN,它發回一個ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將占用一個序號。
(3)服務器B關閉與客戶端A的連接,發送一個FIN給客戶端A。
(4)客戶端A發回ACK報文確認,並將確認序號設置為收到序號加1。
(4)linux查看TCP的狀態命令:
netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}‘
(5)TCP協議的三種狀態
SYN_RECV
服務端收到建立連接的SYN沒有收到ACK包的時候處在SYN_RECV狀態
CLOSE_WAIT
發起TCP連接關閉的一方稱為client,被動關閉的一方稱為server。被動關閉的server收到FIN後,但未發出ACK的TCP狀態是CLOSE_WAIT。出現這種狀況一般都是由於server端代碼的問題,如果你的服務器上出現大量CLOSE_WAIT,應該要考慮檢查代碼。
TIME_WAIT
根據TCP協議定義的3次握手斷開連接規定,發起socket主動關閉的一方 socket將進入TIME_WAIT狀態。TIME_WAIT狀態將持續2個MSL(Max Segment Lifetime),在Windows下默認為4分鐘,即240秒。TIME_WAIT狀態下的socket不能被回收使用. 具體現象是對於一個處理大量短連接的服務器,如果是由服務器主動關閉客戶端的連接,將導致服務器端存在大量的處於TIME_WAIT狀態的socket, 甚至比處於Established狀態下的socket多的多,嚴重影響服務器的處理能力,甚至耗盡可用的socket,停止服務。
描述過程:
Client調用close()函數,給Server發送FIN,請求關閉連接;Server收到FIN之後給Client返回確認ACK,同時關閉讀通道(不清楚就去看一下shutdown和close的差別),也就是說現在不能再從這個連接上讀取東西,現在read返回0。此時Server的TCP狀態轉化為CLOSE_WAIT狀態。
Client收到對自己的FIN確認後,關閉 寫通道,不再向連接中寫入任何數據。
接下來Server調用close()來關閉連接,給Client發送FIN,Client收到後給Server回復ACK確認,同時Client關閉讀通道,進入TIME_WAIT狀態。
Server接收到Client對自己的FIN的確認ACK,關閉寫通道,TCP連接轉化為CLOSED,也就是關閉連接。
Client在TIME_WAIT狀態下要等待最大數據段生存期的兩倍,然後才進入CLOSED狀態,TCP協議關閉連接過程徹底結束。
以上就是TCP協議關閉連接的過程,現在說一下TIME_WAIT狀態。
從上面可以看到,主動發起關閉連接的操作的一方將達到TIME_WAIT狀態,而且這個狀態要保持Maximum Segment Lifetime的兩倍時間。為什麽要這樣做而不是直接進入CLOSED狀態?
原因有二:
一、保證TCP協議的全雙工連接能夠可靠關閉
二、保證這次連接的重復數據段從網絡中消失
先說第一點,如果Client直接CLOSED了,那麽由於IP協議的不可靠性或者是其它網絡原因,導致Server沒有收到Client最後回復的ACK。那麽Server就會在超時之後繼續發送FIN,此時由於Client已經CLOSED了,就找不到與重發的FIN對應的連接,最後Server就會收到RST而不是ACK,Server就會以為是連接錯誤把問題報告給高層。這樣的情況雖然不會造成數據丟失,但是卻導致TCP協議不符合可靠連接的要求。所以,Client不是直接進入CLOSED,而是要保持TIME_WAIT,當再次收到FIN的時候,能夠保證對方收到ACK,最後正確的關閉連接。
再說第二點,如果Client直接CLOSED,然後又再向Server發起一個新連接,我們不能保證這個新連接與剛關閉的連接的端口號是不同的。也就是說有可能新連接和老連接的端口號是相同的。一般來說不會發生什麽問題,但是還是有特殊情況出現:假設新連接和已經關閉的老連接端口號是一樣的,如果前一次連接的某些數據仍然滯留在網絡中,這些延遲數據在建立新連接之後才到達Server,由於新連接和老連接的端口號是一樣的,又因為TCP協議判斷不同連接的依據是socket pair,於是,TCP協議就認為那個延遲的數據是屬於新連接的,這樣就和真正的新連接的數據包發生混淆了。所以TCP連接還要在TIME_WAIT狀態等待2倍MSL,這樣可以保證本次連接的所有數據都從網絡中消失。
參考地址:https://blog.csdn.net/sunyongye/article/details/79007439
TCP/IP協議的學習筆記