做者:Danbo 2015-7-2
本文爲參考TCP/IP詳解卷一,某些知識點加上了做者本身的理解,若有錯誤,歡迎指正,能夠微博聯繫我!java
TCP包格式和IP包格式以下:算法
創建鏈接緩存
TCP協議提供可靠的面向鏈接服務,採用三次握手創建鏈接。
第一次握手:創建鏈接時,客戶端發送SYN包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到SYN包,向客戶端返回ACK(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RCVD狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
完成三次握手,客戶端與服務器開始傳送數據,也就是ESTABLISHED狀態。 服務器
終止鏈接網絡
採用四次揮手斷開雙向鏈接。
(1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送。
(2) 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1。和SYN同樣,一個FIN將佔用一個序號。
(3) 服務器關閉客戶端的鏈接,發送一個FIN給客戶端。
(4) 客戶端發回ACK報文確認,並將確認序號設置爲收到序號加1。併發
TCP狀態變遷圖socket
客戶端的狀態能夠用一下流程圖來表示:ui
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSEDspa
服務器的狀態能夠流程圖:操作系統
CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST->ACK->CLOSED
2MSL等待狀態(兩個做用)
TIME_WAIT狀態也稱爲2MSL等待狀態。每一個具體TCP實現必須選擇一個報文段最大生存時間MSL(Maximum Segment Lifetime)。它是任何報文段被丟棄前在網絡內的最長時間。處理原則:當TCP執行一個主動關閉,併發回最後一個ACK,該連接必須在TIME_WAIT狀態停留的時間爲2MSL。這樣可以讓TCP有機會在此發送最後一個ACK以防這個ACK丟失(在另外一端發送FIN前提)
可是,在鏈接處於2MSL等待時,任何遲到返回的報文段將被丟棄。由於處於2MSL等待的、由該插口對(socket pair)定義的鏈接在這段時間內不能被再用,對於客戶程序還好 一些,可是對於服務程序,例如httpd,它老是要使用同一個端口80來進行服務,而在 2MSL時間內,啓動httpd就會出現錯誤(插口被使用)。爲了不這個錯誤,服務器給出了一個平靜時間(quit time)的概念,這是說在2MSL時間內,雖然能夠從新啓動服務器,可是這個服務器仍是要平靜等待MSL時間才能進行下一次鏈接,讓後來返回的數據包沒有機會影響到發送端,由於返回的包和從新創建的包使用同一個四元組,發送端沒法區分這兩個包屬於不一樣鏈接。(建議MSL時間爲2min,不過這個與操做系統有關。)
半打開狀態(Half-Open)
若是以防已經關閉或異常終止鏈接而另外一方殊不知道,咱們將這樣的TCP鏈接稱爲半打開的。這種狀態能夠經過Keepalive選項來進行發現兩一段已經消失。還有一種形式是:本端發送SYN,對端迴應ACK+SYN,此時本段不迴應ACK。
當處於半打開狀態的一方重啓並從新鏈接後,它將丟失復位前的全部信息,所以它並不知道數據報文段中提到的鏈接。此時就會返回RST(異常終止要發送RST置位的包)包應答,已關閉這次鏈接。此時只須要等待MSL時間,由於TCP默認機器重啓的時間大於MSL。PIX防火牆和IDS入侵檢測系統均可以假裝攻擊目標發送RST的包去終止異常的TCP鏈接。(好比限定鏈接的時間,減小半開鏈接限制超時時間)當咱們Telnet一個不存在的端口號時,本段立馬收到一個拒絕訪問的包,這個就是對方發送的RST包致使的。
半關閉狀態(Half-Close)
單方向鏈路關閉。即TCP鏈接一端在結束它的發送後還能接收來自另外一端數據的能力。程序調用的是shutdown,而不是close,不過大多數程序都是調用close終止兩個方向的鏈接。
最大報文段長度MSS(Option字段)
最大報文段長度表示TCP傳往另外一端的最大塊數據的長度。當創建一個鏈接時,每一方都受到對方通告的MSS值(MSS選項只能出如今SYN報文中)。若是一方收不到另外一方的MSS值,那麼就設爲默認的536字節。MSS是最長見的選項字段,還有另外一個選項叫作窗口放大因子(Window*Shift Count便可以發送超大的數據包,即乘以目前窗口的倍數爲實際一次發送的數據量。解決高速鏈路和高速主機普通TCP發包過慢問題。)。還有一些HASH值也會放在Option字段。而防火牆默認則會清掉IP和TCP的Option選項字段。
一個例子:這裏咱們將舉另一個例子:在一個交互註冊過程當中鍵入中斷的一個特殊功能鍵。這個功能鍵一般能夠產生多個字符序列,常常從ASCII碼的轉移(escape)字符開始,若是TCP每次獲得一個字符,它極可能會發送序列中的第一個字符(ASCII碼的ESC),而後緩存其餘字符並等待對該字符的確認。但當服務器收到該字符後,它並不發送確認而是繼續的等待接受序列中的其餘字符。這就會常常觸發服務器的經受時延的確認算法,表示剩下的字符沒有在200ms內發送。對於交互用戶而言,這將產生明顯的時延。
注意只有客戶端這邊有經受時延的確認,由於客戶端這邊輸入的比較慢,服務器那邊收到數據就會當即確認。最大等待200ms尚未數據發送的話,客戶端就直接返回ACK了。
TCP採用滑動窗口來進行傳輸控制,滑動窗口的大小意味着接收方有多大的緩存區能夠用於接收數據。發送方能夠經過滑動窗口的大小來肯定應該發送多少字節的數據。當滑動窗口爲0時,發送方通常不能再發送數據,可是緊急數據除外,例如:容許用戶終止在遠端機上的運行進程。另外一種狀況是發送方能夠發送一個1字節的數據報來通知接收方從新聲明它但願接收的下一字節及發送方的滑動窗口大小。
滑動窗口機制的基本原理就是在任意時刻,發送方都維持了一個連續的容許發送的幀的序號,稱爲發送窗口,同時,接收方也維持了一個容許接收的幀的序號,稱爲接收窗口。發送窗口和接收窗口的序號的上下界不必定要同樣,甚至大小也可不一樣。不一樣的滑動窗口協議窗口大小通常不一樣。發送窗口內的序號的上下界不必定要同樣,可是尚未被確認的幀,或者是哪些能夠被髮送的幀。
發送方打開幾號窗口表示發送方已經發送了該序列的幀,可是若是沒有獲得接收方ack確認的話,此時該序號的幀仍然在發送窗口中。接收方方打開幾號窗口表明接收端收到幾號的幀,可是並無返回ack確認。當接收方返回該序號的ack時,該序號關閉(合攏),接收方收到ack時,該序號窗口關閉(此時窗口張開,注意始終不能大於通告窗口大小)。
對於發送窗口來講窗口打開表明發送了該序列數據,但沒有收到確認,收到ACK後窗口合攏。
對於接受窗口來講窗口打開表明接受了該序列數據,但沒有發送確認,當發ACK後窗口合攏。
1比特滑動窗口協議
當發送窗口和接收窗口的大小固定爲1時,滑動窗口協議退化爲停等協議(stop-and-wait)。該協議規定發送方每發送一幀後就要停下來,等待接收方已正確接收的確認(Acknowledgement)返回後才能繼續發送下一個幀。因爲發送方須要判斷接收到的幀是新習發的幀仍是從新發送的幀,所以發送放要爲每一個幀加一個序號。因爲停等協議規定只要一幀徹底發送成功後才能發送新的幀,於是只用一比特來編號就夠了。
後退n協議
因爲停等協議要爲每個幀進行確認後才繼續發送下一幀,大大下降了信道利用率,所以又提出了後退n協議。後退n協議中,發送方在發完已給數據幀後 ,不停下來等待應答幀,而是連續發送若干個幀,即便在連續發送過程當中收到了接收方發來的應答幀,也能夠繼續發送。且發送方在每發完一個數據幀時都要設置超時定時器。只要在所設置的超時時間內未收到確認幀,就要重發相應的數據幀。如:當發送方發送了N個幀後,若發現該N幀的前一個幀在計時器超後仍未返回其確認信息,該幀被斷定爲出錯或者丟失,此時發送方就不得不從新發送出錯幀及其後的N幀。
從這裏不難看出,後退n協議一方面因連續發送數據幀而提升了效率,可是另外一方面,在重傳時又必須把原已正確重傳的數據幀進行重傳(僅因這些數據這以前有一個數據幀出錯),這種作法又使重傳效率下降。因而可知,若傳輸信道的傳輸質量不好於是致使誤碼率較大,連續測協議不必定優於中止等待協議。此協議中的發送窗口的大小爲k,接收窗口仍未1.
選擇重傳協議
在後退n協議中,接收方若發現錯誤幀就再也不接收後續的幀,及時是正確的幀到達,這顯然是一種浪費。另外一種效率跟高的策略是當接收方發現某幀出錯後,其後繼續送來的正確的幀雖然不能當即遞交給接收方的高層,但接收方扔可收下來,存放在一個緩衝區,同時要求發送方從新傳輸出錯的那一幀。一旦收到從新傳來的幀後,就能夠源存與緩衝區中國的其他幀一併按正確的順序遞交高層。這種方法稱爲選擇重發(Selectice Repeat),顯然,選擇重發減小了浪費,但要求接收方有足夠大的緩衝區空間。