Swift-SocketServer端粘包处理

仅提供示例,因为每个项目对应的socket消息通讯协议几乎都是不同的,我这里每条消息的消息头占3个字节,其中第2、3字节是消息体长度(不包含消息头,大端模式)

import CocoaAsyncSocket
import UIKit

protocol WSSocketDataDelegate: AnyObject {
    func didReceiveData(data: Data, ip: String?)
}

extension WSSocketDataDelegate {
    func didReceiveData(data: Data, ip: String?) {}
}

private class WSClientDataProt {
    var ip = ""
    var block: ((Data) -> Void)?

    private let queue = OperationQueue()
    private var tcpCacheData = Data()
    
    init() {
        //串行
        queue.maxConcurrentOperationCount = 1
    }

    func unpackMsg(data: Data) {
        queue.addOperation { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.tcpCacheData.append(data)
            while !strongSelf.tcpCacheData.isEmpty {
                var lc: UInt16 = 0
                guard strongSelf.tcpCacheData.count >= 3 else { break }
                (strongSelf.tcpCacheData as NSData).getBytes(&lc, range: NSMakeRange(1, 2))
                let len = Int(UInt16(bigEndian: lc)) + 3
                guard let body = strongSelf.tcpCacheData.getSubData(start: 0, count: len) else { break }
                strongSelf.block?(body)
                strongSelf.removeCacheData(start: 0, num: len)
            }
        }
    }

    private func removeCacheData(start: Int, num: Int) {
        guard start >= 0 && num >= 0 else { return }
        guard tcpCacheData.count >= start + num else { return }
        let startIndex = tcpCacheData.index(tcpCacheData.startIndex, offsetBy: start)
        let endIndex = tcpCacheData.index(tcpCacheData.startIndex, offsetBy: start + num)
        let range = startIndex ..< endIndex
        tcpCacheData.removeSubrange(range)
    }
}

class WSSocketDataManager: NSObject {
    weak var delegate: WSSocketDataDelegate?

    private static var manager: WSSocketDataManager?

    public static var shared: WSSocketDataManager {
        if manager == nil {
            manager = WSSocketDataManager()
        }
        return manager!
    }

    func destroy() {
        WSSocketDataManager.manager = nil
    }

    override private init() {}

    private var clientDataDic = [String: WSClientDataProt]()

    func didReceiveData(data: Data, TCPSock: GCDAsyncSocket? = nil, address: String?) {
        // tcp
        if let sock = TCPSock {
            guard let add = sock.connectedHost else { return }
            if let client = clientDataDic[add] {
                client.unpackMsg(data: data)
            } else {
                let clientData = WSClientDataProt()
                clientData.ip = add
                clientDataDic[add] = clientData
                clientData.block = { [weak self] packet in
                    self?.delegate?.didReceiveData(data: packet, ip: add)
                }
                clientData.unpackMsg(data: data)
            }
        }
        // udp
        else {
            delegate?.didReceiveData(data: data, ip: address)
        }
    }

    // socket断开时调用
    func removeSocketData(sock: GCDAsyncSocket) {
        guard let add = sock.connectedHost else { return }
        clientDataDic.removeValue(forKey: add)
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容