美文网首页
利用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