0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何讓接收端知道發(fā)送端將要發(fā)送的字節(jié)流長(zhǎng)度?

冬至配餃子 ? 來(lái)源:多蘭多 ? 作者:Toranto ? 2022-08-19 09:33 ? 次閱讀

粘包現(xiàn)象展示

一上來(lái)就枯燥的文字,難免容易犯困,所以我先演示一下粘包現(xiàn)象:

pYYBAGL-5cuAOVptAACt-k3cEww678.pngpYYBAGL-5dKAQaAaAACFAIai1xo613.png

我們的預(yù)期是,服務(wù)端打印出hello,I am Toranto這兩個(gè)字符串,兩個(gè)字符串經(jīng)編碼之后的字節(jié)總長(zhǎng)度為17個(gè)字節(jié),但是我們看結(jié)果:

pYYBAGL-5eiAZO4uAAClEv3pYXI844.png

ps:b''是表示字節(jié)的意思,和我們之前用的f''(format)格式化用法是一樣的,單、雙、三引號(hào)一樣??梢粤私庖幌拢?/p>

pYYBAGL-5fmAJFgWAADuKMsMuyQ976.png

好了回歸粘包現(xiàn)象,我們看到上圖,我們采用兩次接收數(shù)據(jù)的方式,兩次都接收20個(gè)字節(jié),但是發(fā)送端發(fā)送的兩次總字節(jié)只有17個(gè)字節(jié)長(zhǎng)度,所以,tcp基于流式的協(xié)議,會(huì)先發(fā)送第一段字節(jié)到一個(gè)緩沖區(qū),如果時(shí)間間隔很短,則tcp會(huì)等第二段字也發(fā)送到這個(gè)緩沖區(qū)再統(tǒng)一發(fā)送到接收端這邊,兩次內(nèi)容的粘合沒(méi)有達(dá)到我們預(yù)期的效果,這就是粘包現(xiàn)象。

粘包

粘包是一種現(xiàn)象,而且只有tcp會(huì)出現(xiàn)粘包現(xiàn)象,udp不會(huì),這是基于tcp的

流式傳輸

導(dǎo)致的,tcp是傳輸數(shù)據(jù)流。

tcp會(huì)將數(shù)據(jù)量較小,且發(fā)送時(shí)間間隔較短的數(shù)據(jù)一起打包發(fā)送,那么這里所講的時(shí)間較短是相比網(wǎng)絡(luò)延遲來(lái)說(shuō)的。比如我們兩次發(fā)送間隔為0.00001s,那么網(wǎng)絡(luò)延遲為0.001s,這個(gè)時(shí)候兩次的數(shù)據(jù)就會(huì)打包發(fā)送,這是一種優(yōu)化機(jī)制,但也就是這個(gè)優(yōu)化機(jī)制導(dǎo)致粘包現(xiàn)象。

首先我們需要了解一下socket收發(fā)數(shù)據(jù)的原理:

pYYBAGL-5hOAUFCWAAB4BXjjpO0413.png


發(fā)送端可以是1K1K地發(fā)送數(shù)據(jù),而接收端的應(yīng)用程序可以兩K兩K地提走數(shù)據(jù),當(dāng)然也有可能一次提走3K或6K數(shù)據(jù),或者一次只提走幾個(gè)字節(jié)的數(shù)據(jù),也就是說(shuō),應(yīng)用程序所看到的數(shù)據(jù)是一個(gè)整體,或說(shuō)是一個(gè)流(stream),一條消息有多少字節(jié)對(duì)應(yīng)用程序是不可見(jiàn)的,因此TCP協(xié)議是面向流的協(xié)議,這也是容易出現(xiàn)粘包問(wèn)題的原因。

UDP是面向消息的協(xié)議,每個(gè)UDP段都是一條消息,應(yīng)用程序必須以消息為單位提取數(shù)據(jù),不能一次提取任意字節(jié)的數(shù)據(jù),這一點(diǎn)和TCP是很不同的。怎樣定義消息呢?可以認(rèn)為對(duì)方一次性write/send的數(shù)據(jù)為一個(gè)消息,需要明白的是當(dāng)對(duì)方send一條信息的時(shí)候,無(wú)論底層怎樣分段分片,TCP協(xié)議層會(huì)把構(gòu)成整條消息的數(shù)據(jù)段排序完成后才呈現(xiàn)在內(nèi)核緩沖區(qū)。

例如基于tcp的套接字客戶端往服務(wù)端上傳文件,發(fā)送時(shí)文件內(nèi)容是按照一段一段的字節(jié)流發(fā)送的,在接收方看來(lái),根本不知道該文件的字節(jié)流從何處開(kāi)始,在何處結(jié)束。

所謂粘包問(wèn)題主要還是因?yàn)榻邮辗讲恢老⒅g的界限,不知道一次性提取多少字節(jié)的數(shù)據(jù)所造成的。

此外,發(fā)送方引起的粘包是由TCP協(xié)議本身造成的,TCP為提高傳輸效率,發(fā)送方往往要收集到足夠多的數(shù)據(jù)后才發(fā)送一個(gè)TCP段。若連續(xù)幾次需要send的數(shù)據(jù)都很少,通常TCP會(huì)根據(jù)優(yōu)化算法把這些數(shù)據(jù)合成一個(gè)TCP段后一次發(fā)送出去,這樣接收方就收到了粘包數(shù)據(jù)。

粘包解決

很遺憾,socket并沒(méi)有給我們提供內(nèi)置解決方法。

那我們需要如何解決?

問(wèn)題的根源在于,接收端不知道發(fā)送端將要發(fā)送的字節(jié)流的長(zhǎng)度。

我們可以基于此點(diǎn)想解決辦法,如何讓接收端知道發(fā)送端將要發(fā)送的字節(jié)流長(zhǎng)度(提前獲知)?

我們可以在發(fā)送端寫一個(gè)提前告知的代碼,并且在接收端循環(huán)判定,是否達(dá)到預(yù)定字節(jié)流長(zhǎng)度,達(dá)到了再一并打印出來(lái):

發(fā)送端和接收端(關(guān)鍵)要結(jié)合起來(lái)看:

poYBAGL-5liADeynAACWEief7aM603.pngpoYBAGL-5maASjQyAAC99PDfsRo576.png

接下來(lái)我把源碼放上來(lái),我加了一些判斷條件:

poYBAGL-5pyAGUpLAAEN4Em8_V4145.pngpoYBAGL-5qKADGyrAACxqV0zfe0603.pngpYYBAGL-5qeAaPxNAADr_s6XptU956.png

演示一下結(jié)果:

pYYBAGL-5-uAA8XNAAFN4_KPLZM724.pngpYYBAGL-5_CAFcRvAABXEcoRNqU369.png



審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 編解碼
    +關(guān)注

    關(guān)注

    1

    文章

    140

    瀏覽量

    19526
  • 字符串
    +關(guān)注

    關(guān)注

    1

    文章

    566

    瀏覽量

    20388
  • 網(wǎng)絡(luò)編程
    +關(guān)注

    關(guān)注

    0

    文章

    66

    瀏覽量

    10013
  • TCP協(xié)議
    +關(guān)注

    關(guān)注

    1

    文章

    89

    瀏覽量

    12048
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    FPGA高速收發(fā)器的GTX發(fā)送解析

    每一個(gè)收發(fā)器擁有一個(gè)獨(dú)立的發(fā)送,發(fā)送有PMA(Physical Media Attachment,物理媒介適配層)和PCS(PhysicalCoding Sublayer,物理編碼
    的頭像 發(fā)表于 11-20 11:27 ?6356次閱讀
    FPGA高速收發(fā)器的GTX<b class='flag-5'>發(fā)送</b><b class='flag-5'>端</b>解析

    ZYNQ進(jìn)階:PLUART 發(fā)送設(shè)計(jì)案例

    在 ZYNQ進(jìn)階之路2 中我們講解了PLPWM呼吸燈的設(shè)計(jì),本節(jié)我們講解PL實(shí)現(xiàn)串口UART的發(fā)送設(shè)計(jì); 首先新建一個(gè)串口發(fā)送的工程,工程建立在ZYNQ進(jìn)階之路1中已經(jīng)講述,這里不
    的頭像 發(fā)表于 11-25 17:26 ?3414次閱讀
    ZYNQ進(jìn)階:PL<b class='flag-5'>端</b>UART <b class='flag-5'>發(fā)送</b>設(shè)計(jì)案例

    HDMI信號(hào)的接收發(fā)送與PD的DFP和UFP有對(duì)應(yīng)關(guān)系嗎?

    HDMI信號(hào)的接收發(fā)送與PD的DFP和UFP有對(duì)應(yīng)關(guān)系嗎? 例如:一作為HDMI的接收
    發(fā)表于 02-29 07:46

    TCP通信的接收發(fā)送字符串的這個(gè)原理是什么???謝謝!

    一個(gè)是 服務(wù)器的 接收部分,一個(gè)是 客戶發(fā)送部分。發(fā)送部分是不是: 先發(fā)送字符串的 長(zhǎng)度
    發(fā)表于 05-06 15:52

    can總線發(fā)送大于八個(gè)字節(jié)數(shù)據(jù)代碼怎實(shí)現(xiàn)

    將要發(fā)送IP報(bào)文所以將要發(fā)送的數(shù)據(jù)遠(yuǎn)遠(yuǎn)大于8個(gè)字節(jié)……現(xiàn)在的思路就是構(gòu)造一個(gè)新的數(shù)據(jù)幀,包含頭和尾還有數(shù)據(jù)的
    發(fā)表于 06-17 14:32

    LWIP UDP如何發(fā)送長(zhǎng)度超過(guò)1500字節(jié)的數(shù)據(jù)?

    環(huán)境:STM32F7 + FREERTOS + LWIP UDP在使用UDP發(fā)送數(shù)據(jù)時(shí),發(fā)現(xiàn)發(fā)送長(zhǎng)度比較大的數(shù)據(jù)時(shí)PC的網(wǎng)絡(luò)助手收不到數(shù)據(jù),一直找BUG,最后看到網(wǎng)上說(shuō)UDP
    發(fā)表于 05-23 19:28

    如何解決lwip的netconn客戶發(fā)送問(wèn)題

    我的板子做客戶,用的lwip,現(xiàn)在在與服務(wù)器連接成功后,發(fā)送有個(gè)問(wèn)題1,在網(wǎng)絡(luò)調(diào)試助手中設(shè)置20ms不停發(fā)送1字節(jié),板子客戶
    發(fā)表于 07-15 04:36

    CC2500不能接收發(fā)送數(shù)據(jù)

    發(fā)送前TXBYTES能讀到寫進(jìn)TX_FIFO中的字節(jié)數(shù),發(fā)送完成后讀到的是0.發(fā)送接收兩邊
    發(fā)表于 03-27 10:22

    如何在發(fā)送發(fā)送逗號(hào)?

    將使用逗號(hào)檢測(cè)和對(duì)齊模塊。但現(xiàn)在我有點(diǎn)困惑。如何在發(fā)送發(fā)送逗號(hào)? 如果我只是使用GTP傳輸PRBS并接收PRBS,我是否必須使用逗號(hào)來(lái)對(duì)齊字節(jié)
    發(fā)表于 06-10 08:56

    如何兩片89C51實(shí)現(xiàn)串行通信,發(fā)送將0~f循環(huán)發(fā)送接收并在接收顯示?

    如何兩片89C51實(shí)現(xiàn)串行通信,發(fā)送將0~f循環(huán)發(fā)送接收并在
    發(fā)表于 09-30 06:27

    在消息列隊(duì)中初始化時(shí)怎么知道發(fā)送消息的長(zhǎng)度

    問(wèn)題:假設(shè)串口1接收了200個(gè)字節(jié),串口接收完成后,通過(guò)消息列隊(duì)把這200個(gè)數(shù)據(jù)發(fā)送給處理線程1,線程1怎么知道串口中斷發(fā)過(guò)來(lái)的是200個(gè)
    發(fā)表于 03-24 09:26

    載波發(fā)送接收端接口電路

    接口電路的實(shí)現(xiàn)  根據(jù)上述的理論分析與建立的數(shù)學(xué)模型,可設(shè)計(jì)出低壓電力線通信發(fā)送的接口電路,如圖2所示。?
    發(fā)表于 10-13 13:54 ?2061次閱讀
    載波<b class='flag-5'>發(fā)送</b><b class='flag-5'>端</b>與<b class='flag-5'>接收</b>端接口電路

    基于系數(shù)可調(diào)FFE的10Gb_s發(fā)送的設(shè)計(jì)

    基于系數(shù)可調(diào)FFE的10Gb_s發(fā)送的設(shè)計(jì)_陳功
    發(fā)表于 01-07 21:39 ?2次下載

    STM32F4發(fā)送接收長(zhǎng)度數(shù)據(jù)的判斷

    STM32F4 串口收發(fā)使用DMA還是很方便的。但是配置DMA時(shí)需要配置數(shù)據(jù)長(zhǎng)度,這一點(diǎn)對(duì)于發(fā)送來(lái)說(shuō)可以預(yù)估計(jì)自己發(fā)送長(zhǎng)度來(lái)配置DMA發(fā)送
    發(fā)表于 11-08 16:25 ?6258次閱讀

    字節(jié)流和字符流有什么區(qū)別?看完就知道

    字節(jié)流和字符流有什么區(qū)別?看完就知道字節(jié)流和字符流是Java I/O系統(tǒng)中的兩個(gè)重要概念,用于處理輸入和輸出的數(shù)據(jù)。 首先,字節(jié)流是以字節(jié)
    的頭像 發(fā)表于 12-09 14:57 ?1318次閱讀