TCP 協(xié)議是面向連接,可靠的流式協(xié)議,當 Server 去 Read 的時候,每次讀到的數(shù)據(jù)都不一定是完整的,該方法會返回讀到的字節(jié)數(shù),因此,當我們寫 Server 的時候,什么時候去回調(diào)用戶設(shè)置的 callback ?也就是怎么樣保證每次都能拿到一個完整的包數(shù)據(jù),這個就是”粘包“問題的由來。
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供建昌網(wǎng)站建設(shè)、建昌做網(wǎng)站、建昌網(wǎng)站設(shè)計、建昌網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、建昌企業(yè)網(wǎng)站模板建站服務,十年建昌做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡服務。
傳統(tǒng)的,有兩種方法解決。一是分隔符協(xié)議,即每條消息結(jié)尾設(shè)置固定分隔符,Server 讀到分隔符就認為讀到了完整的包數(shù)據(jù);二是長度協(xié)議,即在每個消息頭部設(shè)置固定長度的字段,表征消息長度,再往后讀取該長度的消息即可。
目前長度協(xié)議用的較多,因為分隔符協(xié)議需要 Server 不停的檢測,很耗費性能。長度協(xié)議實現(xiàn)中比較重要的點是頭部的長度以及字節(jié)序, 2 個字節(jié)可表示 2^16-1 個字節(jié)的內(nèi)容,如果不夠,那就上4字節(jié),字節(jié)序相關(guān)的只是可以參考: ”字節(jié)序“是什么鬼?
先來個沒處理粘包的:
common/server.go:
測試一下:
因為每次只讀5個字節(jié),可以明顯看到消息”亂了“,但就算把這個值增大,你只要是設(shè)置了,就會存在這個問題。
delimeter/server.go:
還是拿上個測試腳本跑,結(jié)果:
這次看到每個消息長度不一樣,但是都是”完整的“。
length/server.go:
client 也得相應調(diào)整:
測試結(jié)果:
效果跟分隔符協(xié)議一樣,都可以解決”粘包“問題。
只要是 TCP 協(xié)議,任何語言都需要處理 ”粘包“ 問題,我們用 PHP 寫一個客戶端測試一下:
完美!
只有在直接使用 TCP 協(xié)議才存在 "粘包" 問題,其上層應用層協(xié)議比如 HTTP ,已經(jīng)幫我們處理好了,無需關(guān)注這些底層,但是我們自己實現(xiàn)一個自定義協(xié)議,就必須考慮這些細節(jié)了。
2021-03-08
TCP協(xié)議下的粘包與拆包,如何解決一、粘包、拆包1.1 粘包原因1.1.1 滑動窗口1.1.2 Nagle算法1.1.3 應用層原因1.2 拆包原因1.2.1 滑動窗口1.2.2 MSS限制1.2.3 應用層原因1.2 Netty提供的解決方案二、自定義協(xié)議解決粘包、拆包2.1 自定義協(xié)議要素
因為TCP/IP在起初,所有的請求是串行化的,之后做成了滑動窗口的概念。那么在接收方,如果接收不及時且窗口大小足夠大,就可能出現(xiàn)粘包的情況。
因為每次數(shù)據(jù)發(fā)送的時候,都需要加上消息頭等特殊數(shù)據(jù),TCP與IP協(xié)議分別會加20Byte數(shù)據(jù),因此哪怕只是發(fā)送1Byte數(shù)據(jù),最終接收方還是會接收到41Byte;在這樣的背景下,Nagle算法可能會將多個數(shù)據(jù)包合并在一起發(fā)送。
接收方ByteBuf設(shè)置太大(Netty默認為1024Byte),因此如果客戶端發(fā)送的報文都非常小,拋開上述 1.1.1.1 中的原因不談,光在Netty這一處也非常容易出現(xiàn)粘包現(xiàn)象
假設(shè)接收方的窗口只剩128Bytes,發(fā)送方的報文大小是256Bytes,這時放不下了,只能先發(fā)送前128Bytes,等待ack后,窗口有剩余空間了才會發(fā)送剩余部分,這就導致了拆包
當發(fā)送數(shù)據(jù)超過MSS限制后,會將數(shù)據(jù)切分發(fā)送,而這個MSS是根據(jù)不同類型網(wǎng)卡的限制來看,譬如某筆記本網(wǎng)卡可以發(fā)送1500Byte,除去一次數(shù)據(jù)包中的TCP/IP固定40Byte外,真正的數(shù)據(jù)也只能發(fā)送1460Byte。
Netty中ByteBuf設(shè)置的大小小于數(shù)據(jù)包大小。
未完待續(xù)... ...
一、socket 通信粘包的處理方法:
1、對于發(fā)送方引起的粘包現(xiàn)象,用戶可通過編程設(shè)置來避免,TCP提供了強制數(shù)據(jù)立即傳送的操作指令push,TCP軟件收到該操作指令后,就立即將本段數(shù)據(jù)發(fā)送出去,而不必等待發(fā)送緩沖區(qū)滿;
2、對于接收方引起的粘包,則可通過優(yōu)化程序設(shè)計、精簡接收進程工作量、提高接收進程優(yōu)先級等措施,使其及時接收數(shù)據(jù),從而盡量避免出現(xiàn)粘包現(xiàn)象;
3、由接收方控制,將一包數(shù)據(jù)按結(jié)構(gòu)字段,人為控制分多次接收,然后合并,通過這種手段來避免粘包。
二、實現(xiàn)代碼:
三、方法注意事項:
1、第一種編程設(shè)置方法雖然可以避免發(fā)送方引起的粘包,但它關(guān)閉了優(yōu)化算法,降低了網(wǎng)絡發(fā)送效率,影響應用程序的性能,一般不建議使用。
2、第二種方法只能減少出現(xiàn)粘包的可能性,但并不能完全避免粘包,當發(fā)送頻率較高時,或由于網(wǎng)絡突發(fā)可能使某個時間段數(shù)據(jù)包到達接收方較快,接收方還是有可能來不及接收,從而導致粘包;
3、第三種方法雖然避免了粘包,但應用程序的效率較低,對實時應用的場合不適合。
四、實驗環(huán)境
1、硬件環(huán)境:服務器:pentium 350 微機 、客戶機:pentium 166微機、網(wǎng)絡平臺:由10兆共享式hub連接而成的局域網(wǎng);
2、軟件環(huán)境:操作系統(tǒng):windows 98 、編程語言:visual c++ 5.0
分享題目:go語言中tcp協(xié)議粘包 go tcp粘包
網(wǎng)站路徑:http://www.chinadenli.net/article36/dddogsg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、微信小程序、軟件開發(fā)、網(wǎng)站維護、、動態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)