美文网首页
利用CocoaAsyncSocket实现socket客户端(sw

利用CocoaAsyncSocket实现socket客户端(sw

作者: 美洲豹2047 | 来源:发表于2018-02-28 15:32 被阅读0次

    本人第一次使用swift编写客户端,才疏学浅,请高手执教 :)
    CocoaAsyncSocket Github: https://github.com/robbiehanson/CocoaAsyncSocket

    这个应该是最好的socket client 第三方库

    本文章主要介绍自定义协议,使用其他第三方协议可以忽略。

    服务端我用的是Erlang写的,使用了{packet,4}选项,就是说每个数据包前4个字节(bigEndian)代表内容长度。

    要点1:socket收发流程

    mSocket.connect(toHost: "x.x.x.x", onPort: 9000, withTimeout: TimeInterval(1000))
    
    public func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16)
    
    sock.readData(withTimeout: -1, tag: 0)
    
    public func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int)
    
    parse_data(data: data)
    
    sock.readData(withTimeout: -1, tag: 0)
    

    ... ...
    循环收发

    要点2: UInt32 与 Data 之间的转换

    //UInt32 -> Data
    let myuid:UInt32 = 1000
    var uid = myuid.bigEndian
    let data = Data(bytes: &uid, count: MemoryLayout.size(ofValue: uid))
    
    //Data -> UInt32
    let lenByte = data.subdata(in: 0..<PACKET )
    let len = UInt32(bigEndian: lenByte.withUnsafeBytes { $0.pointee })
    

    要点3:为了避免粘包,递归处理数据包
    服务器1秒内发送多个数据包,使用readData会合并起来(如果使用别的协议,有结束符,可以使用别的函数避免这个问题),我采用erlang最常用的尾递归方式,详见下面代码: parse_data ,

    源码:
    Socket处理类:MySocket.swfit

    import Foundation
    import CocoaAsyncSocket
    let PACKET = 4
    public class MySocket: NSObject , GCDAsyncSocketDelegate {
        var mSocket: GCDAsyncSocket!
        var connectStatus = 0
        override init() {
            super.init()
            mSocket = GCDAsyncSocket()
            mSocket.delegate = self
            mSocket.delegateQueue = DispatchQueue.main
        }
        
        public func send(){
            let cmd:UInt8 = 2
            let myuid:UInt32 = 1000
            var uid = myuid.bigEndian
            let str = UIDevice.current.identifierForVendor?.uuidString
            let content = str?.data(using: String.Encoding.utf8)
            var d = Data()
            d.append(cmd)
            d.append(Data(bytes: &uid, count: MemoryLayout.size(ofValue: uid)))
            d.append(content!)
            let contentlen = UInt32(d.count)
            var len = contentlen.bigEndian
            d.insert(contentsOf: Data(bytes: &len, count: MemoryLayout.size(ofValue: len)), at: 0)
            mSocket.write(d, withTimeout: TimeInterval(1000), tag: 0)
        }
        
        public func connect() {
            do {
                connectStatus = 0
                try mSocket.connect(toHost: "x.x.x.x", onPort: 9000, withTimeout: TimeInterval(1000))
            } catch {
                print("conncet error")
            }
        }
        public func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
            parse_data(data: data)
            sock.readData(withTimeout: -1, tag: 0)
        }
        
        public func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
            sock.readData(withTimeout: -1, tag: 0)
            print("success")
        }
        
        public func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
            print("disconnect")
        }
        
        public func parse_data(data:Data){
            let lenByte = data.subdata(in: 0..<PACKET )
            let contentLength = Int(UInt32(bigEndian: lenByte.withUnsafeBytes { $0.pointee }))
            let contentByte   = data.subdata(in: PACKET..<contentLength+PACKET)
            switch contentByte[0] {
                case 1:
                    let flagByte = contentByte[1]
                    let uidByte  = contentByte.subdata(in: 2..<contentByte.count)
                    print(flagByte, UInt32(bigEndian: uidByte.withUnsafeBytes { $0.pointee }))
                    break;
                case 2:
                    let flagByte = contentByte[1]
                    print(flagByte)
                    break;
                default:
                    print("unknow cmd")
            }
            if contentLength+PACKET < data.count {
                parse_data(data: data.subdata(in: contentLength+PACKET..<data.count))
            }
        }
        
    }
    

    在 AppDelegate.swift 中定义全局变量,并初始化

    import UIKit
    
    var mySocket: MySocket?
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        var window: UIWindow?
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            window = UIWindow(frame: UIScreen.main.bounds)
            window?.backgroundColor = Color.white
            mySocket = MySocket()
            //....
    

    相关文章

      网友评论

          本文标题:利用CocoaAsyncSocket实现socket客户端(sw

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