TCP協議詳解(理論篇)

轉載地址:http://blog.csdn.net/lqx0405/article/details/44777087
TCP協議詳解(理論篇)
1.    與UDP不同的是,TCP提供了一種面向連接的、可靠的字節流服務。面向連接比較好理解,就是連接雙方在通信前需要預先建立一條連接,這猶如實際生活中的打電話。助於可靠性,TCP協議中涉及了諸多規則來保障通信鏈路的可靠性,總結起來,主要有以下幾點:
     (1)應用數據分割成TCP認爲最適合發送的數據塊。這部分是通過“MSS”(最大數據包長度)選項來控制的,通常這種機制也被稱爲一種協商機制,MSS規定了TCP傳往另一端的最大數據塊的長度。值得注意的是,MSS只能出現在SYN報文段中,若一方不接收來自另一方的MSS值,則MSS就定爲536字節。一般來講,在不出現分段的情況下,MSS值還是越大越好,這樣可以提高網絡的利用率。
     (2)重傳機制。設置定時器,等待確認包。
     (3)對首部和數據進行校驗。
     (4)TCP對收到的數據進行排序,然後交給應用層。
     (5)TCP的接收端丟棄重複的數據。
     (6)TCP還提供流量控制。(通過每一端聲明的窗口大小來提供的)
2. TCP包的首部:  www.2cto.com  

20120820010645591.jpg
(1)      若不計選項字段,TCP的首部佔20個字節。
(2)      源端口號以及目的端口號用於尋找發端和接收端的進程,一般來講,通過端口號和IP地址,可以唯一確定一個TCP連接,在網絡編程中,通常被稱爲一個socket接口。
(3)      序號是用來標識從TCP發端向TCP接收端發送的數據字節流。
(4)      確認序號包含發送確認的一端所期望收到的下一個序號,因此,確認序號應該是上次已經成功收到數據字節序號加1.
(5)      首部長度指出了TCP首部的長度值,若不存在選項,則這個值爲20字節。
(6)      標誌位(flag):
               URG: 緊急指針有效
               ACK:確認序號有效
               PSH:接收方應儘快將這個報文段交給應用層
               RST:重建連接
               SYN:同步序號用來發起一個連接
               FIN: 發端完成發送任務(主動關閉)    
【解釋】
◆     TCP提供解決方式是爲了使一端告訴另外一端某些“緊急數據”已經放置在普通的數據流中,讓接收端對緊急數據做特別處理。此時,URG位被置爲1,並且16位的緊急數據被置爲一個正的偏移量,通過此偏移量與TCP首部中的序號字段相加,可以得出緊急數據的最後一個字節的序號,常見的應用有傳輸中斷鍵(在通過telnet連接過程中)。
◆     RST: 復位字段被用於當一個報文發送到某個socket接口而出現錯誤時,TCP則會發出復位報文段。常見出現的情況有以下幾種:  www.2cto.com  
發送到不存在的端口的連接請求:此時對方的目的端口並沒有偵聽,對於UDP,將會發出ICMP不可達的   錯誤信息,而對於TCP,將會發出設置RST復位標誌位的數據報。異常終止一個連接:正常情況下,通過發送FIN去正常關閉一個TCP連接,但也有可能通過發送一個復位   報文段去中途釋放掉一個連接。在socketAPI中通過設置socket選 項SO_LINGER去關閉這種異常關閉的情況。
3. TCP的連接與終止過程:

20120820010646840.jpg
(1)  三次握手:
        建立一個TCP連接,必須經歷三次握手過程,其中發送第一個SYN的一端將執行主動打開,接收這個SYN併發回下一個SYN的另一端執行被動打開。
(2)  四次釋放:
        要釋放一個TCP連接,需要通過四次握手過程,這是由TCP的半關閉特性造成的,因爲TCP連接時全雙工的,因此,需要TCP兩端要單獨執行關閉。值得注意的是,主動關閉的一端在發送FIN之後,依然還能正常接收對方的數據,只是通知對方它已經沒有數據需要發送了,同理,被動關閉的一端在收到FIN之後,仍然可以發送數據,直到它自身同樣發出FIN之後,才停止發送數據。
(3)  TCP連接的超時問題:
        完成一個TCP連接,中間涉及到一個超時的問題,大多數伯克利系統的超時時限爲75s,Solaris9的超時時限爲240s,因此,一般認爲是在75-240之間。
【引申】在具體的實現中,如何由用戶自己去完成設置socket連接超時時間?
【解決方法】目前實現socket超時連接主要是通過select來完成的。具體步驟如下:
   ◆     建立socket
   ◆     將socket設置爲非阻塞模式(若是阻塞模式,那麼時間設置就毫無意義)
   ◆     調用connect去進行連接
   ◆     使用select檢查socket是否可寫,並同時判斷其結果(爲什麼是可寫?因爲需要檢測socket是否收到ACK。)
   ◆     將socket轉化爲阻塞模式
(4)TCP的半關閉  www.2cto.com  
        所謂“半關閉”,是指連接的一端在結束它的發送之後還能接收到對方發過來的數據的能力。具體表現在,當完成三次握手的雙方,其中有一端發出FIN,此時它將進入半關
閉狀態,此時它關閉了自身的發送功能,但是它依然可以接收到對方的數據,如對方發過來的ACK消息。那麼在實際開發中,是怎麼實現的呢?
這牽涉到系統中shutdown和close函數的區別問題。
       int shutdown(int s, int how)       <sys/socket.h>
        shutdown是用來終止參數s所指定的socket接口,參數how主要有以下幾種情況:
        how = 0    終止讀取操作
        how = 1    終止寫入操作
        how = 2    終止讀取和寫入操作
        返回的errorcode可能有:
        EBADF  /* Bad file descriptor */
        ENOTSOCK  /* Socket operation on non-socket */
        ENOTCONN  /* Socket is not connected */
【引用】
   Big difference between shutdown and close on a socket is thebehavior when the socket is shared by other processes.A shutdown() affects all copies of the socket whileclose() affects only the file descriptor in one process.
   Even if you close() a TCP socket, it won't necessarily beimmediately reusable anyway, since it will be in a TIME_WAITstate while the OS makes sure there's no outstandingpackets that might get confused as new information if you were to immediatelyreuse that socket for something else.
【注意】
當shutdown關閉讀取部分時,則會丟掉接收緩衝區中的任何數據,並關閉該端的連接,若是關閉寫入部分,TCP則會發送剩餘的數據,然後終止連接的寫入端。
4. TCP的狀態變遷圖:

20120820010647807.jpg
幾個狀態解析:
(1)     TIME_WAIT狀態
   這種狀態也稱爲2MSL等待狀態,MSL即一個報文段的最長生存時間,也就是報文在網絡中被丟棄前的最長時間。那麼爲什麼需要等待2倍的MSL呢?這是因爲在TIME_WAIT狀態之後,需要執行主動關閉,發送ACK,同時還需要加上一倍的MSL,爲了等待對方的反饋結果(是否收到重發的FIN),這是因爲再發送ACK之後,可能因爲諸多原因而導致ACK發送失敗,此時Server端會在此發送FIN。
    正常情況下,client在2MSL期間,對應的socket是不能再被使用的,但是在具體的實現中(如伯克利),則可以通過SO_REUSEADDR選項重用此接口。
(2)     FIN_WAIT_2狀態
    當對方對自己發送的FIN進行了確認,此時將進入FIN_WAIT_2狀態。
(3) CLOSE_WAIT狀態與FIN_WAIT_1狀態
    當連接中的一方收到對方發過來的FIN時,它將進入CLOSE_WAIT狀態,而另一端則進入FIN_WAIT_1狀態。  www.2cto.com  
5. TCP中流量控制機制——滑動窗口
     受到諸多因素的影響,如硬件(雙方網卡吞吐量差異)、網絡環境,網絡極易出現各種各樣的擁塞,目前所採取的措施主要有以下兩種:改進擁塞算法以及控制發送端和接收端的流量。本節主要講述如何在接收端和發送端進行流量控制。
(1)滑動窗口——接收端
     在講解滑動窗口協議之前,可以回顧下最初人們爲了在接收端實施流量控制所提出了的經典算法——停止等待算法,其核心思想是:接收端在收到一個數據報之後,停止接收新的數據報,直到發出ACK(對收到的數據報的確認)之後進行恢復。算法思想以及實現非常簡單,但是卻遇到一個效率的問題,特別是隨着網絡設備的數據處理能力得到了很大的提高,效率低下顯得尤其明顯,後來人們也嘗試了多種改進措施,如本節的滑動窗口就是其中之一。
     其基本原理是:在接收端存在一個接收緩存區,用來接收來自於發送方的數據,只有當應用進程從接收緩存區中取出數據(可能只是部分)併發出其ACK後,纔算作這部分數據已經接收,然後調節此時的滑動窗口大小。發送方根據返回的窗口大小,計算出所能發送的數據大小。因此,可以這麼理解,滑動窗口算法是接收端作爲主動方根據自身的緩存以及處理能力主動去調節對方的發送流量的一種調節算法。
     下面通過一個滑動窗口模型圖瞭解下發送方是如何處理所收到的滑動窗口的?

20120820010648344.jpg
在發送方依然存在一個緩存區(發送緩存區),其發送的數據可以是下面幾種狀態:
◆ 發送並確認 (1-3)
◆ 發送但未確認 (4-6)  www.2cto.com  
◆ 可以發送 (7-9)
◆ 不能夠發送 (10以後)
     值得注意的是,滑動窗口是基於所收到的確認序列號的。當發送方根據所收到的確認序列號以及窗口大小,不斷向後移動,並相應更新數據狀態。
(2)滑動窗口——發送端(擁塞窗口)
    網絡擁塞出現的原因是多方面的,除了收發兩段的硬件差異之外,還與網絡通信鏈路相關,如通信鏈路中轉發路由器的緩存,試想這樣一種情況,若發送端與接收端的處理能力以及吞吐能力很強,若它僅僅通過接收端所返回的滑動窗口大小,難以阻止數據報在被路由器轉發過程中因爲阻塞而被丟棄的情形,因爲與發送端相連的路由器因爲自身的緩衝空間的限制,難以存儲並轉發這麼多數據而出現丟包現象。那麼這種情況如何避免呢?最好的機制是中間的路由器也要參與給發送端反饋窗口大小的事情,也正是本節所說的擁塞窗口。
     綜合上面的闡述,發送端會收到兩個窗口大小,分別是來自於接收端和中間路由器,注意前者在每次的數據報中都會出現,而後者只是在網絡中出現擁塞時由中間路由器發送。那麼,發送方此時取接收端的窗口大小與擁塞窗口中的最小值作爲發送上限值。
發佈了24 篇原創文章 · 獲贊 29 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章