Socket粘包,拆包處理

在iOS中用socket做即時通訊時,經(jīng)常會遇到粘包的問題。

什么是粘包?

粘包:socket傳輸數(shù)據(jù)是由多個連續(xù)的數(shù)據(jù)包組成,他們被連續(xù)的存儲在緩存中,在讀取數(shù)據(jù)包時可能由于某些原因?qū)е芦@取到了錯誤的發(fā)送邊界,這時后就會出現(xiàn)后一個數(shù)據(jù)包的頭連接在了前一個數(shù)據(jù)包的尾部。

怎么解決粘包?

因為TCP協(xié)議是基于字節(jié)流的,所以在應(yīng)用層就要自己解決數(shù)據(jù)的邊界問題。
一般來說,定義數(shù)據(jù)有兩種方式,定義長度 或者 定義一個終結(jié)符。
下面通過項目中的代碼來解釋怎么解決粘包。

func didReadData(_ data:Data){
        //接收的數(shù)據(jù)先寫入緩存
        cache += [UInt8](data)
        while cache.count>8 {
            print("讀取到數(shù)據(jù),開始解析,剩余數(shù)據(jù)長度:\(cache.count)")
            //0-4位存儲消息類型
            let typeBytes = cache[0..<4]
            //4-8位存儲數(shù)據(jù)包長度
            let lengthBytes = cache[4..<8]
            let typeData = Data(typeBytes)
            let lengthData = Data(lengthBytes)
            //注意大小端轉(zhuǎn)換問題
            let type = Int32(bigEndian: typeData.withUnsafeBytes { $0.baseAddress!.bindMemory(to: Int32.self, capacity: 4).pointee })
            let length = Int32(bigEndian: lengthData.withUnsafeBytes { $0.baseAddress!.bindMemory(to: Int32.self, capacity: 4).pointee })
            //數(shù)據(jù)包長度不夠,跳出循環(huán),繼續(xù)讀取笑一個包
            if cache.count < 8+Int(length){
                break
            }
            //獲取到完整的數(shù)據(jù)包
            let resultBytes = cache[8..<8+Int(length)]
            let resultData = Data(resultBytes)
            //將數(shù)據(jù)傳給delegate進(jìn)行處理
            self.delegate?.socketDidRead(type: type, data: resultData,retry:true)
            //沾包循環(huán)讀取
            let begin = 8+Int(length)
            let end = cache.count
            cache = Array(cache[begin..<end])
        }
        sendSocket?.readData(withTimeout: -1, tag: 0)
    }

主要流程如下
1、將接收的數(shù)據(jù)保存到緩存數(shù)據(jù)中。
2、while循環(huán)去讀數(shù)據(jù),直到判斷緩存是否小于8。(0-4字節(jié)為消息類型,4-8為消息長度)
3、循環(huán)中去判斷緩存數(shù)據(jù)是否大于內(nèi)容的長度,如果大于,則解析掉這條數(shù)據(jù),并從緩存中刪除,如果緩存數(shù)據(jù)還有大于8字節(jié)長度的數(shù)據(jù),則循環(huán)讀取數(shù)據(jù)。
如果數(shù)據(jù)長度小于獲取到的內(nèi)容長度,則說明出現(xiàn)粘包,則繼續(xù)readData,繼續(xù)拼接緩存數(shù)據(jù)。

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

相關(guān)閱讀更多精彩內(nèi)容

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