粘包現(xiàn)象展示
一上來就枯燥的文字,難免容易犯困,所以我先演示一下粘包現(xiàn)象:
我們的預(yù)期是,服務(wù)端打印出hello,I am Toranto這兩個(gè)字符串,兩個(gè)字符串經(jīng)編碼之后的字節(jié)總長度為17個(gè)字節(jié),但是我們看結(jié)果:
ps:b''是表示字節(jié)的意思,和我們之前用的f''(format)格式化用法是一樣的,單、雙、三引號一樣??梢粤私庖幌拢?/p>
好了回歸粘包現(xiàn)象,我們看到上圖,我們采用兩次接收數(shù)據(jù)的方式,兩次都接收20個(gè)字節(jié),但是發(fā)送端發(fā)送的兩次總字節(jié)只有17個(gè)字節(jié)長度,所以,tcp基于流式的協(xié)議,會(huì)先發(fā)送第一段字節(jié)到一個(gè)緩沖區(qū),如果時(shí)間間隔很短,則tcp會(huì)等第二段字也發(fā)送到這個(gè)緩沖區(qū)再統(tǒng)一發(fā)送到接收端這邊,兩次內(nè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ò)延遲來說的。比如我們兩次發(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ù)的原理:
發(fā)送端可以是1K1K地發(fā)送數(shù)據(jù),而接收端的應(yīng)用程序可以兩K兩K地提走數(shù)據(jù),當(dāng)然也有可能一次提走3K或6K數(shù)據(jù),或者一次只提走幾個(gè)字節(jié)的數(shù)據(jù),也就是說,應(yīng)用程序所看到的數(shù)據(jù)是一個(gè)整體,或說是一個(gè)流(stream),一條消息有多少字節(jié)對應(yīng)用程序是不可見的,因此TCP協(xié)議是面向流的協(xié)議,這也是容易出現(xiàn)粘包問題的原因。
而UDP是面向消息的協(xié)議,每個(gè)UDP段都是一條消息,應(yīng)用程序必須以消息為單位提取數(shù)據(jù),不能一次提取任意字節(jié)的數(shù)據(jù),這一點(diǎn)和TCP是很不同的。怎樣定義消息呢?可以認(rèn)為對方一次性write/send的數(shù)據(jù)為一個(gè)消息,需要明白的是當(dāng)對方send一條信息的時(shí)候,無論底層怎樣分段分片,TCP協(xié)議層會(huì)把構(gòu)成整條消息的數(shù)據(jù)段排序完成后才呈現(xiàn)在內(nèi)核緩沖區(qū)。
例如基于tcp的套接字客戶端往服務(wù)端上傳文件,發(fā)送時(shí)文件內(nèi)容是按照一段一段的字節(jié)流發(fā)送的,在接收方看來,根本不知道該文件的字節(jié)流從何處開始,在何處結(jié)束。
所謂粘包問題主要還是因?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并沒有給我們提供內(nèi)置解決方法。
那我們需要如何解決?
問題的根源在于,接收端不知道發(fā)送端將要發(fā)送的字節(jié)流的長度。
我們可以基于此點(diǎn)想解決辦法,如何讓接收端知道發(fā)送端將要發(fā)送的字節(jié)流長度(提前獲知)?
我們可以在發(fā)送端寫一個(gè)提前告知的代碼,并且在接收端循環(huán)判定,是否達(dá)到預(yù)定字節(jié)流長度,達(dá)到了再一并打印出來:
發(fā)送端和接收端(關(guān)鍵)要結(jié)合起來看:
接下來我把源碼放上來,我加了一些判斷條件:
演示一下結(jié)果:
審核編輯:劉清
-
編解碼
+關(guān)注
關(guān)注
1文章
140瀏覽量
19635 -
字符串
+關(guān)注
關(guān)注
1文章
585瀏覽量
20561 -
網(wǎng)絡(luò)編程
+關(guān)注
關(guān)注
0文章
72瀏覽量
10088 -
TCP協(xié)議
+關(guān)注
關(guān)注
1文章
91瀏覽量
12100
發(fā)布評論請先 登錄
相關(guān)推薦
評論