1. 程式人生 > >TCP 流協議和訊息分幀的理解

TCP 流協議和訊息分幀的理解

TCP是一種流協議(stream protocol)。這就意味著資料是以位元組流的形式傳遞給接收者的,沒有固有的"報文"或"報文邊界"的概念。從這方面來說,讀取TCP資料就像從串列埠讀取資料一樣--無法預先得知在一次指定的讀呼叫中會返回多少位元組。

為了說明這一點,我們假設在主機A和主機B的應用程式之間有一條TCP連線,主機A上的應用程式向主機B傳送一條報文。進一步假設主機A有兩條報文要傳送,並兩次呼叫send來發送,每條報文呼叫一次。很自然就會想到從主機A向主機B傳送的兩條報文是作為兩個獨立實體,在各自的分組中傳送的,如圖2-25所示。

 
圖2-25 傳送兩條報文的錯誤模型
但不幸的是,實際的資料傳輸過程很可能不會遵循這個模型。主機A上的應用程式會呼叫send,我們假設這條寫操作的資料被封裝在一個分組中傳送給B。實際上,send通常只是將資料複製到主機A的TCP/IP棧中,就返回了。由TCP來決定(如果有的話)需要立即傳送多少資料
。做這種決定的過程很複雜,取決於很多因素,比如傳送視窗(當時主機B能夠接收的資料量),擁塞視窗(對網路擁塞的估計),路徑上的最大傳輸單元(沿著主機A和B之間的網路路徑一次可以傳輸的最大資料量),以及連線的輸出佇列中有多少資料。更多與此有關的內容請參見技巧15。圖2-26只顯示了主機A的TCP封裝資料時可能使用的諸多方法中的4種。在圖2-26中,M11和M12表示M1的第一和第二部分,M21和M22與之類似。如圖2-26所示,TCP不一定會將一條報文的全部內容都放在一個分組中傳送出去。
 
圖2-26 封裝兩條報文可能採用的4種方式

現在,我們從主機B應用程式的角度來看這種情形。總的來說,主機B應用程式任意一次呼叫recv時,都不會對TCP傳送給它的資料量做任何假設。比如,當主機B應用程式讀取第一條報文時,可能會出現下列4種結果。

實際上,可能的結果不止4種,但我們忽略了出錯和EOF之類的結果。我們還假設應用程式讀取了所有可讀的資料。

(1)沒有資料可讀,應用程式阻塞,或者recv返回一條指示說明沒有資料可讀。到底會發生什麼情況取決於套接字是否標識為阻塞,以及主機B的作業系統為系統呼叫recv指定了什麼樣的語義。

(2)應用程式獲取了報文M1中的部分而不是全部資料。比如,傳送端TCP像圖2-26D那樣對資料進行分組就會發生這種情況。

(3)應用程式獲取了報文M1中所有的資料,除此之外沒有任何其他內容。如果像圖2-26A那樣對資料分組就會發生這種情況。

(4)應用程式獲取了報文M1的所有資料,以及報文M2的部分或全部資料。如果像圖2-26B或圖2-26C那樣對資料進行分組就會發生這種情況。

注意,這裡還有一個定時問題。如果主機B的應用程式在主機A傳送了第二條報文之後一段時間內都沒有讀取第一條報文,那麼這兩條報文都會成為可讀的。這就和圖2-26B所示情況相同了。這些描述說明,通常,在任意指定時刻,可讀的資料量都是不確定的。

需要再次說明的是,TCP是一個流協議(stream protocol),儘管資料是以IP分組的形式傳輸的,但分組中的資料量與send呼叫中傳送給TCP多少資料並沒有直接關係。而且,接收程式也沒有什麼可靠的方法可以判斷資料是如何分組的,因為在兩次recv呼叫之間可能會有多個分組到來。

即使接收端應用程式的響應非常及時,也可能會發生這種情況。例如,一個分組丟失了(參見技巧12,在當今的因特網中,這是非常常見的情況),而且後繼分組都安全到達,TCP會將後繼分組中的資料儲存起來,直到重傳第一個分組並正確收到為止。此時,所有資料對應用程式都是可用的。

TCP會記錄它傳送了多少位元組,以及確認的位元組,但它不會記錄這些位元組是如何分組的。實際上,有些實現在重傳丟失分組的時候傳送的資料可能比原來的多一些或少一些。這就足以支撐下面再次重複說明的內容了。

對TCP應用程式來說,就沒有"分組"這種概念。如果應用程式的設計與TCP對資料的分組方式有所關聯,就應該考慮重新設計這個應用程式了。

既然任意一次指定的讀操作中返回的資料量都是不可預測的,就必須在應用程式中做好應對這種情況的準備。通常這不是什麼問題。比如說,我們可能在用fgets這樣標準的I/O庫程式讀取資料。在這種情況下,fgets會將位元組流劃分成行。圖3-6顯示了一個這樣的例子。在其他情況下的確需要關注報文邊界問題,而這些情況下邊界都是由應用程式級維護的。

最簡單的情況就是定長報文。在這種情況下,只需要讀取報文中固定數量的位元組就可以了。根據前面的討論,讀操作返回的位元組數可能小於sizeof(msg)(圖2-26D),所以只進行

recv(s, msg, sizeof(msg), 0); 

處理這種情況的標準方法,完成資料的完整接收:
int readn(SOCKET fd, char *buf, size_t len)
{
     int cnt = len;
     int recvlen;
     recvlen = recv(fd, buf, cnt, 0)
     if(recvlen < 0)
     {
        /* EINTR: function was interrupted by a signal that was caught, before any data was available */
            if(errno == EINTR)
                  continue;
             return -1;
      }
      /* EOF */
      if(recvlen == 0)
         return len - cnt;
     
      buf += recvlen;
      cnt -=  recvlen;
   }
   return len;
}     

簡單理解:

TCP是流協議,不區分流邊界,如果不分幀,那麼可能會發生你send了無數次,但是對方只接收一次的情況

client 傳送位元組流時,TCP會保證server 按順序接收到全部的位元組流,其他諸如資料包的大小等,TCP協議對我們來說是透明的,我們可以全部不考慮。

    通俗點說,我們傳送資料只需要呼叫send函式,我們只需要關注send函式的返回值,從而知道了傳送了多少個位元組,在服務端,我們呼叫recv函式,我們只需要關注recv函式的返回值,從而知道接收了多少個位元組,其他情況通通不管。

   在TCP通訊過程中,我們不需要關心(也沒法關心,但可以設定)資料包的大小,個數,我們只需要在客戶端建立一個緩衝區不斷髮送,在服務端建立一個緩衝區不斷接收就夠了,當然,我們還可以定義一個包頭,來實現諸如傳送檔案這樣更強大的功能。

這就是TCP通訊的本質,不會應平臺的不同而改變


相關推薦

TCP 協議訊息理解

TCP是一種流協議(stream protocol)。這就意味著資料是以位元組流的形式傳遞給接收者的,沒有固有的"報文"或"報文邊界"的概念。從這方面來說,讀取TCP資料就像從串列埠讀取資料一樣--無法預先得知在一次指定的讀呼叫中會返回多少位元組。 為了說明這一點,我們假設在主機A和主機B的應用程式之間

tcp協議產生的粘包問題解決方案

ssize_t readn(int fd, void *buf, size_t count) {     size_t nleft = count;     ssize_t nread;     char *bufp = (char *)buf;     while (nleft > 0)     {

【網路】tcp控制擁塞控制

名詞解釋 MTU:最大傳輸單元(硬體規定),指的是ip頭+data的最大位元組數(資料包超過該值會分片,主要為UDP協議) TTL:資料報的壽命(經過一個路由器減1,工作在ip層) RTO:重傳超時時間 cwnd:傳送視窗 rwnd:接受視窗 流控制 目的: 防止傳送方速率太快,接受端承受不了(

【網絡】tcp控制擁塞控制

一個 tcp 大小設置 邊界 協議 流控制 才會 ttl 大小 名詞解釋 MTU:最大傳輸單元(硬件規定),指的是ip頭+data的最大字節數(數據包超過該值會分片,主要為UDP協議) TTL:數據報的壽命(經過一個路由器減1,工作在ip層) RTO:重傳超時時間 cwnd

IK最細力度智慧理解

public class TokenStreamTest {  public static void main(String[] args) throws IOException  {   String zhText1 = "網廳";   Analyzer ikAnalyzer = new IKAnalyze

python連結資料庫SQL Server 2005出錯怎麼辦???附解決方案以及開啟TCP/IP協議檢視預設埠的過程

import pymssql conn=pymssql.connect(host='127.0.0.1:1433',user='sa',password='jxn',database='scott',charset="UTF-8") ''' 如果和本機資料庫互動,只需修改連結

【Java TCP/IP Socket程式設計】----傳送接收資料----訊息與解析

目錄   簡介 成幀與解析 成幀技術案例 簡介 在程式中使用套接字向其他程式提供資訊或者使用其他程式提供的資訊,這就需要任何需要交換資訊的程式間在資訊編碼方式上達成共識(包含了資訊交換的形式和意義),稱為協議,用來實現特定的應用程式的協議叫應用程式協議。大部分應

TCP/UDP協議——資料資料包

TCP/UDP協議——資料流和資料包 資料流可以分成多個有序的資料包。 TCP傳輸:有連線的資料流服務。tcp提供可靠的傳輸機制,也就是說只要是被髮送的資料都會被接收方接收到,並且雙方也知道被正確接收了。 UDP傳輸:無連線的資料報服務。udp不負責可靠傳輸,他只知道盡最大的努力把資料傳

TCP/IP協議-封裝

資料進入協議棧時的封裝過程 由於TCP、UDP、ICMP和IGMP都要向IP傳送資料,因此IP必須在生成的IP首部中加入某種標識,以表明資料屬於哪一層。為此, IP在首部中存入一個長度為8 bit的數值,稱作協議域。 1表示為ICMP協議,2表示為IGMP協議,6表示為TC

【Java TCP/IP Socket】應用程式協議訊息的成與解析(含程式碼)

     程式間達成的某種包含了資訊交換的形式和意義的共識稱為協議,用來實現特定應用程式的協議叫做應用程式協議。大部分應用程式協議是根據由欄位序列組成的離散資訊定義的,其中每個欄位中都包含了一段以

TCP/IP協議族-----22、萬維網HTTP

art class ip協議 post term fill 技術分享 clas data- TCP/IP協議族-----22、萬維網和HTTP

TCP-IP詳解卷3:TCP 事務協議、HTTP、NNTPUNIX域協議》【PDF】下載

維護 tcp協議 zha 簡介 參考文獻 源程序 .com 的人 ntp TCP-IP詳解卷3:TCP 事務協議、HTTP、NNTP和UNIX域協議》【PDF】下載鏈接: https://u253469.pipipan.com/fs/253469-230062539

OSI模型TCP/IP協議族(一)

出了 框架 調用 數據表 http n+1 互連 改變 2-2 1990年以前,再數據通信和組網文獻中占主導地位的分層模型是開放系統互連(Open System Interconnnection,OSI)模型。當時所有人都認為OSI模型將是數據通信的最終標準,然而這種情況並

OSI模型TCP/IP協議族(二)

出發 app 另一個 改變 cati mar int 點對點 本機 OSI模型中的各層 物理層 物理層(physical layer)協調通過物理媒體傳送比特流時所需要的各種功能。物理層涉及到接口和傳輸媒體的機械和電器規約。它還定義了這些物理設備即接口為了實現傳輸必須完成的

TCP的揮手協議握手協議

自己 -s style 分析 建立 丟失 size lai 透明 三次握手協議:三次握手協議的主要過程是交互彼此之間的初始序列號,如果沒有確認的ACK幀可以麽?肯定是可以的 client A -------> server B client A 發送了自己的初始序列號

深入淺出理解 TCP/IP 協議 (一)

https 分代 讀數 傳輸數據 應用程序 個數 消息 作用 十進制 文章轉自:https://www.cnblogs.com/onepixel/p/7092302.html   TCP/IP 協議棧是一系列網絡協議的總和,是構成網絡通信的核心骨架,它定義了電子設備如何連入

TCP/IP協議三次握手四次揮手大白話解說

ini 存在 detail 系統 超時 定時 com 又能 ssi TCP/IP協議三次握手和四次揮手大白話解說 前言 昨天晚上被一位師傅問到了TCP/IP的工作機制,心裏很清楚三次握手,然而對於四次揮手卻忘了,這是大學習裏學過的,奮而翻閱書籍和網絡對之前所學的做一個溫

談談surging引擎的tcp、http、ws協議如何容器化部署

spro inter span ppi package completed module out 選址 1、前言 分布式已經成為了當前最熱門的話題,分布式框架也百花齊放,群雄逐鹿。從中心化服務治理框架,到去中心化分布式服務框架,再到分布式微服務引擎,這

通俗理解TCP/IP協議三次握手四次分手流程

https 客戶端 四次揮手 謝謝 special csdn tails spec 走了 轉自:https://blog.csdn.net/special23/article/details/54137298 三次握手流程 客戶端發個請求“開門吶,我要進

Linux 從網卡到TCP IP協議棧數據跟蹤與審計

軟中斷 sys load 一個 註冊 linux rst 是否 ring 前沿 在學代碼審計,然後最近做Linux協議棧的審計,發現Linux不愧是一個久經考驗的系統,本來以為可以找到個DoS的,結果發現其在TCP/IP協議棧的鏈路層實現,利用了各種技術,用來提高性能與安全