美文网首页
Socket粘包,拆包处理

Socket粘包,拆包处理

作者: 柠檬君Air | 来源:发表于2022-03-11 08:29 被阅读0次

    在iOS中用socket做即时通讯时,经常会遇到粘包的问题。

    什么是粘包?

    粘包:socket传输数据是由多个连续的数据包组成,他们被连续的存储在缓存中,在读取数据包时可能由于某些原因导致获取到了错误的发送边界,这时后就会出现后一个数据包的头连接在了前一个数据包的尾部。

    怎么解决粘包?

    因为TCP协议是基于字节流的,所以在应用层就要自己解决数据的边界问题。
    一般来说,定义数据有两种方式,定义长度 或者 定义一个终结符。
    下面通过项目中的代码来解释怎么解决粘包。

    func didReadData(_ data:Data){
            //接收的数据先写入缓存
            cache += [UInt8](data)
            while cache.count>8 {
                print("读取到数据,开始解析,剩余数据长度:\(cache.count)")
                //0-4位存储消息类型
                let typeBytes = cache[0..<4]
                //4-8位存储数据包长度
                let lengthBytes = cache[4..<8]
                let typeData = Data(typeBytes)
                let lengthData = Data(lengthBytes)
                //注意大小端转换问题
                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 })
                //数据包长度不够,跳出循环,继续读取笑一个包
                if cache.count < 8+Int(length){
                    break
                }
                //获取到完整的数据包
                let resultBytes = cache[8..<8+Int(length)]
                let resultData = Data(resultBytes)
                //将数据传给delegate进行处理
                self.delegate?.socketDidRead(type: type, data: resultData,retry:true)
                //沾包循环读取
                let begin = 8+Int(length)
                let end = cache.count
                cache = Array(cache[begin..<end])
            }
            sendSocket?.readData(withTimeout: -1, tag: 0)
        }
    

    主要流程如下
    1、将接收的数据保存到缓存数据中。
    2、while循环去读数据,直到判断缓存是否小于8。(0-4字节为消息类型,4-8为消息长度)
    3、循环中去判断缓存数据是否大于内容的长度,如果大于,则解析掉这条数据,并从缓存中删除,如果缓存数据还有大于8字节长度的数据,则循环读取数据。
    如果数据长度小于获取到的内容长度,则说明出现粘包,则继续readData,继续拼接缓存数据。

    相关文章

      网友评论

          本文标题:Socket粘包,拆包处理

          本文链接:https://www.haomeiwen.com/subject/jwofdrtx.html