兩個報文是如何進行 TCP 分組傳輸


 

16 | 如何理解TCP的“流”? https://time.geekbang.org/column/article/132443

TCP 是一種流式協議在前面的章節中,我們講的都是單個客戶端 - 服務器的例子,可能會給你造成一種錯覺,好像 TCP 是一種應答形式的數據傳輸過程,比如發送端一次發送 network 和 program 這樣的報文,在前面的例子中,我們看到的結果基本是這樣的:

發送端:network ----> 接收端回應:Hi, network

發送端:program -----> 接收端回應:Hi, program

這其實是一個假象,之所以會這樣,是因為網絡條件比較好,而且發送的數據也比較少。

為了讓大家理解 TCP 數據是流式的這個特性,我們分別從發送端和接收端來闡述。

 

我們知道,在發送端,當我們調用 send 函數完成數據“發送”以后,數據並沒有被真正從網絡上發送出去,只是從應用程序拷貝到了操作系統內核協議棧中,至於什么時候真正被發送,取決於發送窗口、擁塞窗口以及當前發送緩沖區的大小等條件。也就是說,我們不能假設每次 send 調用發送的數據,都會作為一個整體完整地被發送出去。

 

如果我們考慮實際網絡傳輸過程中的各種影響,假設發送端陸續調用 send 函數先后發送 network 和 program 報文,那么實際的發送很有可能是這個樣子的。

第一種情況,一次性將 network 和 program 在一個 TCP 分組中發送出去,像這樣:...xxxnetworkprogramxxx...

第二種情況,program 的部分隨 network 在一個 TCP 分組中發送出去,像這樣:TCP 分組 1:...xxxxxnetworkproTCP 分組 2:gramxxxxxxxxxx...

第三種情況,network 的一部分隨 TCP 分組被發送出去,另一部分和 program 一起隨另一個 TCP 分組發送出去,像這樣。TCP 分組 1:...xxxxxxxxxxxnetTCP 分組 2:workprogramxxx...

 

實際上類似的組合可以枚舉出無數種。不管是哪一種,核心的問題就是,我們不知道 network 和 program 這兩個報文是如何進行 TCP 分組傳輸的。

 

換言之,我們在發送數據的時候,不應該假設“數據流和 TCP 分組是一種映射關系”。就好像在前面,我們似乎覺得 network 這個報文一定對應一個 TCP 分組,這是完全不正確的。

如果我們再來看客戶端,數據流的特征更明顯。

 

我們知道,接收端緩沖區保留了沒有被取走的數據,隨着應用程序不斷從接收端緩沖區讀出數據,接收端緩沖區就可以容納更多新的數據。

 

如果我們使用 recv 從接收端緩沖區讀取數據,發送端緩沖區的數據是以字節流的方式存在的,無論發送端如何構造 TCP 分組,接收端最終受到的字節流總是像下面這樣:xxxxxxxxxxxxxxxxxnetworkprogramxxxxxxxxxxxx

關於接收端字節流,有兩點需要注意:第一,這里 netwrok 和 program 的順序肯定是會保持的,也就是說,先調用 send 函數發送的字節,總在后調用 send 函數發送字節的前面,這個是由 TCP 嚴格保證的;

第二,如果發送過程中有 TCP 分組丟失,但是其后續分組陸續到達,那么 TCP 協議棧會緩存后續分組,直到前面丟失的分組到達,最終,形成可以被應用程序讀取的數據流。

 

如果我們再來看客戶端,數據流的特征更明顯。我們知道,接收端緩沖區保留了沒有被取走的數據,隨着應用程序不斷從接收端緩沖區讀出數據,接收端緩沖區就可以容納更多新的數據。如果我們使用 recv 從接收端緩沖區讀取數據,發送端緩沖區的數據是以字節流的方式存在的,無論發送端如何構造 TCP 分組,接收端最終受到的字節流總是像下面這樣:xxxxxxxxxxxxxxxxxnetworkprogramxxxxxxxxxxxx關於接收端字節流,有兩點需要注意:第一,這里 netwrok 和 program 的順序肯定是會保持的,也就是說,先調用 send 函數發送的字節,總在后調用 send 函數發送字節的前面,這個是由 TCP 嚴格保證的;第二,如果發送過程中有 TCP 分組丟失,但是其后續分組陸續到達,那么 TCP 協議棧會緩存后續分組,直到前面丟失的分組到達,最終,形成可以被應用程序讀取的數據流。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM