粘包問題和解決方法

什么是粘包問題

發(fā)送方發(fā)送的若干包數(shù)據(jù)到接收方時(shí)粘成一包,從接受緩沖區(qū)來看就是后一包數(shù)據(jù)的頭緊接著前一包數(shù)據(jù)的尾。

粘包出現(xiàn)的原因

發(fā)送方等待到緩沖區(qū)滿才將包發(fā)送出去

若連續(xù)幾次發(fā)送數(shù)據(jù)都很小,tcp會(huì)根據(jù)優(yōu)化算法把這些數(shù)據(jù)整合成一包后一次性發(fā)送,這樣接收方就收到了粘包數(shù)據(jù)。

接收方不及時(shí)接受緩沖區(qū)的包,造成多個(gè)包接收

接收方會(huì)先把收到的數(shù)據(jù)放在系統(tǒng)接收緩沖區(qū),用戶進(jìn)程從該緩沖區(qū)讀取數(shù)據(jù),若下一包數(shù)據(jù)到達(dá)時(shí)前一包數(shù)據(jù)尚未被用戶進(jìn)程取走,則下一包數(shù)據(jù)進(jìn)入緩沖區(qū)時(shí)就到前一包數(shù)據(jù)之后,而用戶進(jìn)程根據(jù)預(yù)先設(shè)定的緩沖區(qū)大小從系統(tǒng)中讀取數(shù)據(jù),這樣便一次取了很多包。

解決方法--封包和解包

發(fā)送方在發(fā)送數(shù)據(jù)的包前,加入數(shù)據(jù)長(zhǎng)度,將數(shù)據(jù)包的結(jié)構(gòu)變成[dataLen|data]的結(jié)構(gòu)再進(jìn)行發(fā)送。而接收方通過解析這種結(jié)構(gòu),從而將多個(gè)數(shù)據(jù)包聚合形成的粘包分解成一個(gè)個(gè)獨(dú)立的數(shù)據(jù)包。具體核心代碼如下所示:
發(fā)送方封包:

const (
    DataLen = 4
)

//封裝數(shù)據(jù)包
func Packet(message []byte) []byte {
    return append(IntToBytes(len(message)), message...)
}

接收方解包:

const (
    DataLen = 4
)

//解包
func Unpack(buffer []byte, readerChannel chan []byte) []byte {
    length := len(buffer)

    var i int
    for i = 0; i < length; i++ {
        if length < i + DataLen {
            break
        }
        //根據(jù)長(zhǎng)度來獲取數(shù)據(jù)
        messageLen := BytesToInt(buffer[i:i+DataLen])
        if length < i + DataLen + messageLen {
            break
        }
        data := buffer[i+DataLen:i+DataLen+messageLen]
        readerChannel <- data

        i += DataLen + messageLen - 1
    }

    if i == length {
        return make([]byte, 0)
    }
    return buffer[i:]
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容