iOS swift5 整合 CocoaAsyncSocket三方庫 實現socket tcp通訊


由於第一次接觸 iOS開發,走了相當多的彎路。

 

最開始使用的是 CocoaAsyncSocket 三方庫,剛開始有好多網上寫好的代碼,作為一個新人,就面向百度編程唄,這一面相可出事了,折騰了兩天都沒折騰明白!

最開始參考的swift 版本 : https://www.jianshu.com/p/9d629bae702f

扒下來,放到我的代碼中。控制台如下:

2021-07-19 11:27:05.373514+0800 NB_Music[5478:1899448] [connection] nw_connection_copy_connected_path [C1] Client called nw_connection_copy_connected_path on unconnected nw_connection
2021-07-19 11:27:05.373790+0800 NB_Music[5478:1899448] [] tcp_connection_is_cellular No connected path
2021-07-19 11:27:05.581082+0800 NB_Music[5478:1899445] [connection] nw_endpoint_handler_set_adaptive_read_handler [C1 192.168.1.144:557 ready socket-flow (satisfied (Path is satisfied), viable, interface: en0, scoped, ipv4, dns)] unregister notification for read_timeout failed
2021-07-19 11:27:05.581260+0800 NB_Music[5478:1899445] [connection] nw_endpoint_handler_set_adaptive_write_handler [C1 192.168.1.144:557 ready socket-flow (satisfied (Path is satisfied), viable, interface: en0, scoped, ipv4, dns)] unregister notification for write_timeout failed

一開始,我以為這是報錯了。經過各種上網的查詢,得出結論,這個玩意好像沒有啥用,就是一個提示他並不是報錯。

然后我就又開始找,上面的代碼可以連接上socket服務,但是不能接收消息,也不能發送消息,一開始以為是有什么參數沒有配置,后來找了各種各樣的 CocoaAsyncSocket 三方庫的swift代碼,發現從鏈接到發送再到接收都是這樣,並沒有缺少哪一段。

期間有的東西可能是swift版本不同,所以參數改變了:

代碼中 dispatch_get_main_queue() 參數變成了 => DispatchQueue.main

其他的基本xcode都會有提示,跟着提示點 fix就可以了!

 

回歸正題,這種方式各種失敗所以我又開始了上網,去查找代碼的問題。過程中發現了有人說需要繼承 NSObject,最開始沒有當一回事,后來成功之后發現可能是這個原因。

我又換了 socketio三方庫,同樣控制台還是現實上面那一段。

 

之后經過了各種查詢,這幾個搜索引擎可能都快被我問煩了。我終於找到一篇文章:https://zhuanlan.zhihu.com/p/40163604

這篇文章同樣是使用 CocoaAsyncSocket 三方庫。我抱着死馬當活馬醫的態度,試了一下,成功了!他就這么成功了!你說氣不氣人!

之后我又各種總結,終於發現我原來的 socket類繼承的是UiViewControll 而這個繼承的就是 NSObject 。。。。

 

到此,我的iOS socket服務鏈接基本成功了!

粘貼一下代碼:

SocketManage.swift 

//
//  SocketManage.swift
//  *****
//
//  Created by seventeen on 2021/7/19.
//

import Foundation
import UIKit
import CocoaAsyncSocket

class SocketManage: NSObject {
    
    static let shared = SocketManage()
    
    let serverPort: UInt16 = UInt16(557)//添加端口
    let serveripInput:String = "192.168.1.144"//添加IP
    var diction : NSDictionary?
    var clientSocket:GCDAsyncSocket!
    var noti: Notification?//用於接收到服務器回傳數據后發送成功通知

    fileprivate var timer: Timer?
    
    private override init() {
        super.init()
        self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector:  #selector(timerAction), userInfo: nil, repeats: true)
        RunLoop.main.add(timer!, forMode: RunLoop.Mode.common)
        self.timer?.fireDate = Date.distantFuture
    }

    /**
     *計時器每秒觸發事件
     **/
    @objc func timerAction() -> Void {
        sendMessage(self.diction as? [String : Any], type: 1001)
    }
    
    /**
     * 銷毀計時器
     **/
    func destroyTimer(){
        self.timer?.invalidate()
        self.timer = nil
    }

    /**
     * 連接服務器
     **/
    
    func connectServer(){
        
        clientSocket = GCDAsyncSocket()
        clientSocket.delegate = self
//        clientSocket.delegateQueue = DispatchQueue.global()
        clientSocket.delegateQueue = DispatchQueue.main
        do {
            try clientSocket.connect(toHost: serveripInput, onPort: serverPort)
        } catch {
            print("try connect error: \(error)")
        }

    }
    /**
     * 消息數據包裝
     **/
    
    /**
     * 字段   Length         type           boby
     * 長度   Int:4byte     Int:4byte    jsonString
     * 釋義   boby長度       自定義類型       數據內容
     * 以上信息不固定和服務端提前定好解析回傳數據也一樣
     *  type  1001
     **/
    func sendMessage(_ serviceDic:[String:Any]?,type:Int){
       
        //print("type---> \(type)")
        
        var bodyDatas = Data()
        if serviceDic != nil{

           bodyDatas = try! JSONSerialization.data(withJSONObject: serviceDic!,options: .prettyPrinted)
            
        }else{
           bodyDatas.count = 4
        }

        var b:UInt32 = CFSwapInt32HostToBig(UInt32(type))
        let typeData = Data(bytes: &b, count: 4)
        
        print("typeData---------\(typeData.description)")

        //Length
        
        var len:UInt32 = CFSwapInt32HostToBig(UInt32(bodyDatas.count + 1))
        let lengthData = Data(bytes: &len, count: 4)
        var byteLengthData = Data()
        for bytesss in lengthData.reversed() {
            byteLengthData.append(bytesss)
        }

        //向服務器進行寫數據
        clientSocket.write(lengthData, withTimeout: -1, tag: 0)
        clientSocket.write(typeData, withTimeout: -1, tag: 0)
        clientSocket.write(bodyDatas, withTimeout: -1, tag: 0)
    }
    
}

extension SocketManage:GCDAsyncSocketDelegate{
    
    /**
     * 連接服務器 成功
     **/
    func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) -> Void {
        
        print("Socket 連接服務器成功")
        //需要向服務器傳遞的數據
        let dic:[String : Any] = ["sessionId":"87878","udid":"HelloiOS"]
        //發送數據以及之前和服務器定好的類型
        sendMessage(dic, type: 1001)
        self.diction = dic as NSDictionary
        clientSocket.readData(withTimeout: -1, tag: 0)

        //連接成功后 啟動定時器 發送心跳
//        timer?.fireDate = Date.distantPast
    }
    
    /**
     * 連接服務器 失敗
     **/
    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Swift.Error?) -> Void {
        //print("Socket 連接服務器失敗: \(String(describing: err))")
        self.timer?.fireDate = Date.distantFuture
        connectServer()
    }
    
    /**
     * 處理服務器發來的消息
     **/
    
    func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) -> Void {

        //print("---Data Recv---")
        
        var byteArr:[UInt8] = []
        var lengthData:[UInt8] = []
        var typeBytesArr:[UInt8] = []
        var bodyBytesArr:[UInt8] = []
        var i = 0
        
        let type:Int = 0
        var length:UInt32 = 0
        let msg = String(data: data as Data, encoding: String.Encoding.utf8)
        print("收到了數據:\(msg)")
        for byte in data {
            if i < 4 {
                lengthData.append(byte)
            }
            let array : [UInt8] = lengthData
            let data = Data(array)
            length = UInt32(bigEndian: data.withUnsafeBytes { $0.pointee })
            if i >= 4 && i < 8{
                typeBytesArr.append(byte)
            }
            
            if i >= 8 && i < length + 7{
                bodyBytesArr.append(byte)
            }
            byteArr.append(byte)
            i += 1
        }
  
        //print("Bytes--->\(byteArr)")
        //print("lengthData ---> \(lengthData)")
        
        let bodyData = Data(bytes: bodyBytesArr, count: bodyBytesArr.count)
        print("收到了數據:\(bodyData)")
        print("---------------------------------------------")
//        //將二進制流轉化為json數據
//        let bodyMs = JSON(bodyData)
//
//        let bodyDic = bodyMs.dictionaryObject
//        if bodyDic != nil{
//            print("\(data)")
//            print("body -->\(bodyMs)")
//        }
    
        if type == 6{
            //print(" ")
        }
        //解析完數據 發送通知 對應地方接收處理
        noti = Notification(name:NSNotification.Name(rawValue: "SocketManageNotification"), object: nil, userInfo: nil)
        NotificationCenter.default.post(noti!)
        //每次讀完數據后,都要調用一次監聽數據的方法
        clientSocket.readData(withTimeout: -1, tag: 0)
    }

}

這里面有包括 發送心跳 ,因為我還在測試,所以我將發送心跳的代碼注釋了!

 

說的不一定對,希望如果大佬看到了能指出錯誤,記錄下來也希望對各位ios開發新手能有所幫助!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM