1. 程式人生 > >python中黏包現象

python中黏包現象

通訊 大小 結構 也有 rec 科學 特點 sendto 次數

#黏包:發送端發送數據,接收端不知道應如何去接收造成的一種數據混亂現象.

#關於分包和黏包:
    #黏包:發送端發送兩個字符串"hello"和"word",接收方卻一次性接收到"helloword"
    #分包:發送端發送字符串"helloword",接收方卻受到了兩個字符串"hello"和"word"
#雖然socket環境有這些問題,但是TCP傳輸數據能保證幾點:
    #順序不變,發送端發送hello,接收方一點順序接收hello,這個TCP協議的特點,成為了
        #解決分包,黏包問題的關鍵.
    #分割的包中間不會插入其它數據
    #註意:
        #如果用socket通訊,就一定要自己定義一份協議,目前的標準協議是:消息頭部(包頭)+消息長度+消息正文
#TCP協議的拆包機制:
    #當發送緩沖區的長度大於網卡的MTU時,tcp會將這次發送的數據拆分成幾個數據包發出去
    #MTU是Maximum Transmission Unit的縮寫.意思是網絡上傳送的最大數據包.MTU的單位是字節
    #大部分網絡設備的MTU都是1500.如果本機的MTU比網關的MTU大,大的數據包就會被拆分傳送
    #這樣會產生很多數據包碎片,增加丟包率,降低網絡數據.

#面向字節流的通信特點和Nagle算法
    #TCP是面向連接的,面向流的,提供高可靠性服務
    #收發兩端(客戶端和服務端)都要有成對的socket,因此,發送端為了將多個發往接收端的包,更有效的
    #發到對方,使用了優化方法(Nagle算法),將多次間隔較小的數據量小的數據合並成一個大的數據塊,然後打包發送
    #這樣,接收端,接收端就很難分辨出來,必須提供科學的拆包機制.即面向流的通信是無邊界保護的
    #註意:
        #對於空消息:tcp是基於數據流,於是收發的消息不能為空,需要在程序服務端和客戶端添加空消息處理機制,防止程序
                    #卡住,而udp是基於數據報的,即使你輸入的是空內容,也可以被發送,udp協議會幫助你封裝上消息的頭
                    #發送過去
        #可靠黏包的tcp協議:tcp的協議數據不會丟失,沒有收完包,下次接收,會繼續上次繼續接收,接收端
                        #總是在收到ack時才會清除緩沖區內容.數據是可靠的,但是黏包.
        # tcp黏包的成因:
                #socket客戶端 <<<<<<<<用戶態>>>>>>socket服務端
                #    ^|                                 ^|
                #    ^|                                 ^|
                #    ^|                                 ^|
                #   緩存<<<<<<<<<<  內核態  >>>>>>>>>>>緩存

        #socket數據傳輸過程中的用戶態與內核態說明:
            #發送端可以是一K一K地發送數據,而接收端的應用程序可以兩K兩K地提走數據
            # 當然也有可能一次提走3K或6K數據,或者一次只提走幾個字節的數據。
            # 也就是說,應用程序所看到的數據是一個整體,或說是一個流(stream),
            # 一條消息有多少字節對應用程序是不可見的,因此TCP協議是面向流的協議,
            # 這也是容易出現粘包問題的原因。 而UDP是面向消息的協議,每個UDP段都是一條消息,
            # 應用程序必須以消息為單位提取數據,不能一次提取任意字節的數據, 這一點和TCP是很不同的。
            # 怎樣定義消息呢?可以認為對方一次性write/send的數據為一個消息,
            # 需要明白的是當對方send一條信息的時候,無論底層怎樣分段分片
            # TCP協議層會把構成整條消息的數據段排序完成後才呈現在內核緩沖區。

    #例如基於tcp的套接字客戶端往服務端上傳文件,發送時文件內容是按照一段一段的字節流發送的,
    # 在接收方看了,根本不知道該文件的字節流從何處開始,在何處結束
    # 此外,發送方引起的粘包是由TCP協議本身造成的,TCP為提高傳輸效率,
    # 發送方往往要收集到足夠多的數據後才發送一個TCP段。若連續幾次需要send的數據都很少,
    # 通常TCP會根據優化算法把這些數據合成一個TCP段後一次發送出去,這樣接收方就收到了粘包數據。

#UDP不會發生黏包現象:
    #UDP是無連接的,面向數據報,提供高效率服務
    #不會使用塊的合並優化算法,, 由於UDP支持的是一對多的模式,所以接收端的skbuff(套接字緩沖區)
    # 采用了鏈式結構來記錄每一個到達的UDP包,在每個UDP包中就有了消息頭(消息來源地址,端口等信息),
    # 這樣,對於接收端來說,就容易進行區分處理了。 即面向消息的通信是有消息保護邊界的。
    # 對於空消息:tcp是基於數據流的,於是收發的消息不能為空,這就需要在客戶端和服務端都添加空消息的處理機制
    # ,防止程序卡住,而udp是基於數據報的,即便是你輸入的是空內容(直接回車),也可以被發送,
    # udp協議會幫你封裝上消息頭發送過去。 不可靠不黏包的udp協議:udp的recvfrom是阻塞的,
    # 一個recvfrom(x)必須對唯一一個sendinto(y),收完了x個字節的數據就算完成,若是y;x數據就丟失,
    # 這意味著udp根本不會粘包,但是會丟數據,不可靠。

#註意:
    #udp和tcp一次發送數據長度的限制
    #用UDP協議發送時,用sendto函數最大能發送數據的長度為:65535- IP頭(20) – UDP頭(8)=65507字節。
    # 用sendto函數發送數據時,如果發送數據長度大於該值,則函數會返回錯誤。(丟棄這個包,不進行發送)
    # 用TCP協議發送時,由於TCP是數據流協議,因此不存在包大小的限制(暫不考慮緩沖區的大小),
    # 這是指在用send函數時,數據長度參數不受限制。而實際上,所指定的這段數據並不一定會一次性發送出去,
    # 如果這段數據比較長,會被分段發送,如果比較短,可能會等待和下一次數據一起發送。
    #
    #數據鏈路層:
        #因為網卡的MTU一般被限制在1500
         #數據鏈路層大小限制 1500-ip包頭(20)-udp包頭(8) = 1472
         # if sendto(num)
         #  num > 65507  報錯
         #  1472< num < 65507   會在數據鏈路層拆分
         #udp本身是不可靠協議,一旦解包,會造成數據丟失
         #  num < 1472 是比較理想的狀態

  

python中黏包現象