一、什么是TCP的拆包和粘包?
粘包:比如客戶端發(fā)送了第一個(gè)數(shù)據(jù)包內(nèi)容為abc,然后又發(fā)送了第二個(gè)數(shù)據(jù)包為bcd,服務(wù)端接收到了數(shù)據(jù),內(nèi)容是abcbcd,對(duì)于接收數(shù)據(jù)的服務(wù)端來(lái)說(shuō),是無(wú)法區(qū)分哪些內(nèi)容是哪個(gè)數(shù)據(jù)包的,也無(wú)法區(qū)分客戶端到底發(fā)送了幾個(gè)數(shù)據(jù)包。當(dāng)然了也許不止2個(gè)數(shù)據(jù)包粘在一塊。這樣的情況就稱為粘包。
粘包
拆包:比如客戶端發(fā)送了2個(gè)數(shù)據(jù)包,服務(wù)端也收到了2個(gè)數(shù)據(jù)包,但是這2個(gè)數(shù)據(jù)包屬于同一條消息,因?yàn)橄⑻蟮仍颍徊鸪闪藥讉€(gè)數(shù)據(jù)包發(fā)送。這樣的情況就稱為拆包。
拆包
二、為什么會(huì)出現(xiàn)TCP的拆包和粘包?
看到這里你可能會(huì)問(wèn),為什么會(huì)出現(xiàn)TCP的拆包和粘包,而沒(méi)聽(tīng)說(shuō)過(guò)UDP會(huì)出現(xiàn)拆包和粘包呢?它們不都是傳輸層協(xié)議嗎?
其實(shí)UDP協(xié)議真的沒(méi)有拆包和粘包的問(wèn)題,只有TCP協(xié)議有,為什么呢?因?yàn)門CP是流式協(xié)議,每次發(fā)送數(shù)據(jù)都會(huì)有一個(gè)固定的大小,為了提高TCP傳輸?shù)男阅埽l(fā)送端會(huì)把數(shù)據(jù)發(fā)送到一個(gè)緩沖區(qū),當(dāng)緩沖區(qū)滿了后,再把緩沖去中的數(shù)據(jù)發(fā)送到接收端,同樣的接收端也是同樣的機(jī)制來(lái)接收數(shù)據(jù)。
因此當(dāng)發(fā)送端需要發(fā)送的內(nèi)容大于緩沖區(qū)的大小,就會(huì)發(fā)生拆包的現(xiàn)象,當(dāng)發(fā)送端的內(nèi)容太小,就容易發(fā)生粘包的現(xiàn)象,導(dǎo)致不同的消息一起發(fā)送給接收方。當(dāng)接收方不能及時(shí)獲取消息時(shí)也會(huì)導(dǎo)致粘包的現(xiàn)象發(fā)生。
除了拆包和粘包還有一個(gè)詞語(yǔ)叫做半包,那么什么是半包呢?
半包就是發(fā)送的數(shù)據(jù)包包含了整個(gè)消息的一部分,這樣的數(shù)據(jù)包就叫做半包。
那么為什么UDP協(xié)議不會(huì)發(fā)生拆包和粘包呢?因?yàn)閁DP協(xié)議每個(gè)消息是相互獨(dú)立的,發(fā)送方發(fā)送一次,和接收方接收一次是一一對(duì)應(yīng)的,比如,發(fā)送方發(fā)送了abc,然后又發(fā)送了bcd,那么接收方接收一次內(nèi)容是abc,接收方再接收一次才是bcd,因此UDP協(xié)議不會(huì)出現(xiàn)拆包和粘包的問(wèn)題。
三、常用的解決TCP的拆包和粘包的方案有哪些?
我們已經(jīng)了解了粘包和拆包的發(fā)生的原因,那么有什么解決方案呢?常用的方案又是哪些呢?
常用的解決方法有四種:
1.消息是定長(zhǎng)的,報(bào)文長(zhǎng)度固定,比如設(shè)定一個(gè)報(bào)文長(zhǎng)度為300,如果實(shí)際內(nèi)容不夠300就用空格占位。
2.在報(bào)文的尾部添加特殊的分隔符,接收方通過(guò)特殊的分隔符來(lái)區(qū)分報(bào)文的結(jié)尾。
3.將消息分為消息頭和消息尾,在消息的頭部使用標(biāo)識(shí)表名信息的總長(zhǎng)度。
4.使用更加復(fù)雜的自定義的應(yīng)用層協(xié)議。