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)
    }
}

你可能感兴趣的:(Swift-SocketServer端粘包处理)