Swift-SocketServer端粘包處理

僅提供示例,因?yàn)槊總€(gè)項(xiàng)目對應(yīng)的socket消息通訊協(xié)議幾乎都是不同的,我這里每條消息的消息頭占3個(gè)字節(jié),其中第2、3字節(jié)是消息體長度(不包含消息頭,大端模式)

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斷開時(shí)調(diào)用
    func removeSocketData(sock: GCDAsyncSocket) {
        guard let add = sock.connectedHost else { return }
        clientDataDic.removeValue(forKey: add)
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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