TCP----面向連接、可靠性、效率的實現

之前我們看了TCP的報頭內容,那麼TCP的到底是怎樣實現的呢?

首先,爲了保證TCP的可靠性,都表現在以下幾個方面:

1.面向連接

      首先,TCP是面向連接的,那麼什麼是面向連接呢?就是在通信之前讓雙方感知到對方的存在並讓發送方發送數據給接收方;在通信之後,關閉連接。那麼又是怎麼建立/斷開連接-----三次握手/四次揮手。

                         

如上圖兩個圖,就是客戶端和服務端進行三次握手/四次揮手的過程。其中仍有很多的問題需要解答:

1.爲什麼建立是三次握手,關閉時四次揮手?

     當建立連接時,客戶端發送SYN請求給服務端,服務端同時相應ACK+SYN給客戶端,客戶端發送ACK認爲建立連接成功,發送數據,但最後一條消息沒有相應的ACK確認,所以不能保證最後一條的可靠性,也就意味着最後一條報文丟失時,對服務端沒有什麼影響。當關閉連接時,服務端收到FIN的報文,並不會立即關閉SOCKET,因爲後可能還有別的報文在傳輸,所以先響應ACK給客戶端,當傳輸完成後,服務端再告知(發送FIN)給客戶端,客戶端響應ACK確認關閉。

2.能不能兩次握手建立連接?

      不能,若兩次握手建立連接當最後一條報文(服務端給客戶端響應ACK+SYN)丟失,服務端認爲建立連接成功,花費一些成本去維護這條連接;而客戶端則認爲沒有建立成功,就會再請求連接,導致服務端上充滿大量的SYN_RECV狀態的“半連接”,造成SYN洪水。而當三次握手的最後一條報文服務端沒有收到,則服務端不認爲連接建立成功,所以維護連接的成本不由服務端承擔,當客戶端發送數據時,服務端會響應RST(重新建立連接)。

2.確認應答

     下圖,就是數據傳輸確認應答的機制,主機B會相應給主機A下一個接收消息的序號,這個序號爲A發送的消息+1響應給主機A。通過序列號和確認序號來確保通信的可靠性,當接收端收到消息,會返回一個收到消息的通知。這個消息就是確認應答ACK。TCP通過確認應答來確保傳輸的可靠性,當收到應答,代表收到消息;否則,就會認爲數據丟失,就會觸發操作----重傳,這樣,即使丟包,也能保證傳輸。

                                                            

3.超時重傳

    在特定的一段時間內,若沒有收到確認應答,就會認爲丟包,引起重傳。這時,就會有兩種情況,第一種是B沒有收到消息,即在發送的時候消息就丟失;第二種是A沒有收到確認應答,它會認爲B沒有收到消息,這兩種情況都會引起重傳。

但是,對於第二種來說,B實際上是收到了數據的,如果這種情況出現多的話,對於B來說,是無謂的消耗。所以第二次接收到相同的數據時,TCP協議能識別重複的包文,將其丟棄,達到去重的作用。而去重是由序列號做到的。

                                         

4.粘包問題

    對於TCP來說,傳輸方式是面向字節流的,在創建一個TCP的socket套接字時,在內會中會爲之創建發送和接收緩衝區,當有讀寫操作時,並不從網絡上直接讀取數據,而都是先從緩衝區中拿數據。對於TCP的一個連接,既可以讀數據,也可以寫數據,所以也叫全雙工。對於TCP來說,它的可靠性可以用多種機制來保證,但是,TCP是面向字節流的,這樣就會面臨一個問題----粘包

在傳輸層看,TCP報文是按照序號排放在緩衝區中的。但是,在應用層,並不能感知到他們的分界,而是認爲他們是一串連續的字節。這樣拿取數據就會出現粘包的問題。那麼怎麼區分每個數據包的邊界呢?1.定長的報文,每次按照固定大小讀取。2.對於變長的包,可以在包頭的位置,將報文的長度告知;也可以將每個包文用特定的分隔符來區分邊界。

5.流量控制

      在TCP報頭中,有一個字段是窗口大小。表示接收緩衝區的剩餘大小。那是因爲接收端的處理速度是有限的,若發送端的發送速度過快,接收端的緩衝區佔滿,來不及處理,就會導致丟包。因此就提出了窗口大小。告知發送端自己的緩衝區的剩餘大小,那樣,發送端接收到時,就會根據情況來改變傳輸的速率。不讓接收端處於超負荷工作,導致丟包等一系列問題。

 

爲了提高TCP的效率,有以下的方法。

    在數據傳輸時間過長的時候,若發送端每發送一個數據段,就響應一個ACK,收到ACK之後,再發送下一個數據段。這樣在路程中就會浪費很多時間,所以就有以下幾種機制來解決效率的問題:   

1.滑動窗口

      滑動窗口提出了,每次發送多條數據(將多條的時間重疊在一起) ,以此提高性能。滑動窗口大小就是指無需等待確認應答可以繼續發送數據的最大量。這種機制使用大量的緩衝區,通過對多個段同時確認應答的功能。

                                                   

    上圖所表示的窗口大小就是4000個字節。就意味着發送四個段的報文,不需要等待ACK,直接將其發送。 那麼同時發送四個包,怎麼能保證TCP傳輸的可靠性呢?如下兩個圖,操作系統爲了保證傳輸的可靠性,每收到一個ACK的報文,將窗口向後滑動一個包的大小,從緩衝區刪掉。      

                     

      那麼,如果發生丟包,會怎麼處理呢?1.當主機B收到數據包,但是響應的ACK丟失,這樣實際上包文是收到了的所以丟了一個ACK並不會影響,因爲會有下一個確認應答進行確認。但是,若沒有使用窗口控制,主機A沒有收到ACK,就會認爲B沒有收到,所以會重發數據包。2.假設數據包1001~2000發送時丟掉,主機B沒有收到,但響應的是上一個1~1000這個報文所對應的1001的ACK,但是2001~3000和3001~4000這兩個報文安全到達,B會連續響應兩個1001的ACK,當A收到三個同樣的一個ACK,會重發那個包文。當B收到1001時,再次返回的ACK是4001,因爲之前的報文已經在接收緩衝區中。

2.擁塞控制

     有了滑動窗口,可以高效可靠的發送數據。但是在剛開始發送數據的時候並不能發送大量的數據。因爲,當前的網絡狀況若是較差,一次性發送過多的數據會導致更多的丟包,所以,就引入了慢啓動。先試探發送少量的包文,再根據情況增加報文的發送。根據慢啓動的算法提出了擁塞窗口:下圖就是慢開始和擁塞窗口的關係。

                           

    在擁塞控制中還引入了快重傳:快重傳指接收方連續收到三個重複確認N的報文段(代表接收端並未收到N報文)。在這時,就不需要再等待設置的重傳計時器時間到期。

     

3.延遲應和答捎帶應答

延遲應答指的是接收端處理包文的窗口較小但處理速度快,就會有延遲應答,用來積壓報文,以便一次性多處理,提高效率。

捎帶應答是雙方通信都需要給發送數據,就不用在浪費一個報文專門只用來應答的。

TCP異常情況

當進程終止後,仍然會發送FIN包,和正常關閉一樣

當網絡突然出現問題,TCP內部會有一個保活定時器,會定期詢問對方是否在線,如果不在的話,自己會釋放連接

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章