粘包現象展示
一上來就枯燥的文字,難免容易犯困,所以我先演示一下粘包現象:
我們的預期是,服務端打印出hello,I am Toranto這兩個字符串,兩個字符串經編碼之后的字節總長度為17個字節,但是我們看結果:
ps:b''是表示字節的意思,和我們之前用的f''(format)格式化用法是一樣的,單、雙、三引號一樣??梢粤私庖幌拢?/p>
好了回歸粘包現象,我們看到上圖,我們采用兩次接收數據的方式,兩次都接收20個字節,但是發送端發送的兩次總字節只有17個字節長度,所以,tcp基于流式的協議,會先發送第一段字節到一個緩沖區,如果時間間隔很短,則tcp會等第二段字也發送到這個緩沖區再統一發送到接收端這邊,兩次內容的粘合沒有達到我們預期的效果,這就是粘包現象。
粘包
粘包是一種現象,而且只有tcp會出現粘包現象,udp不會,這是基于tcp的
流式傳輸
導致的,tcp是傳輸數據流。
tcp會將數據量較小,且發送時間間隔較短的數據一起打包發送,那么這里所講的時間較短是相比網絡延遲來說的。比如我們兩次發送間隔為0.00001s,那么網絡延遲為0.001s,這個時候兩次的數據就會打包發送,這是一種優化機制,但也就是這個優化機制導致粘包現象。
首先我們需要了解一下socket收發數據的原理:
發送端可以是1K1K地發送數據,而接收端的應用程序可以兩K兩K地提走數據,當然也有可能一次提走3K或6K數據,或者一次只提走幾個字節的數據,也就是說,應用程序所看到的數據是一個整體,或說是一個流(stream),一條消息有多少字節對應用程序是不可見的,因此TCP協議是面向流的協議,這也是容易出現粘包問題的原因。
而UDP是面向消息的協議,每個UDP段都是一條消息,應用程序必須以消息為單位提取數據,不能一次提取任意字節的數據,這一點和TCP是很不同的。怎樣定義消息呢?可以認為對方一次性write/send的數據為一個消息,需要明白的是當對方send一條信息的時候,無論底層怎樣分段分片,TCP協議層會把構成整條消息的數據段排序完成后才呈現在內核緩沖區。
例如基于tcp的套接字客戶端往服務端上傳文件,發送時文件內容是按照一段一段的字節流發送的,在接收方看來,根本不知道該文件的字節流從何處開始,在何處結束。
所謂粘包問題主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所造成的。
此外,發送方引起的粘包是由TCP協議本身造成的,TCP為提高傳輸效率,發送方往往要收集到足夠多的數據后才發送一個TCP段。若連續幾次需要send的數據都很少,通常TCP會根據優化算法把這些數據合成一個TCP段后一次發送出去,這樣接收方就收到了粘包數據。
粘包解決
很遺憾,socket并沒有給我們提供內置解決方法。
那我們需要如何解決?
問題的根源在于,接收端不知道發送端將要發送的字節流的長度。
我們可以基于此點想解決辦法,如何讓接收端知道發送端將要發送的字節流長度(提前獲知)?
我們可以在發送端寫一個提前告知的代碼,并且在接收端循環判定,是否達到預定字節流長度,達到了再一并打印出來:
發送端和接收端(關鍵)要結合起來看:
接下來我把源碼放上來,我加了一些判斷條件:
演示一下結果:
審核編輯:劉清
-
編解碼
+關注
關注
1文章
145瀏覽量
20062 -
字符串
+關注
關注
1文章
589瀏覽量
21228 -
網絡編程
+關注
關注
0文章
72瀏覽量
10593 -
TCP協議
+關注
關注
1文章
101瀏覽量
12399
發布評論請先 登錄
FPGA高速收發器的GTX發送端解析

ZYNQ進階:PL端UART 發送設計案例

評論