由于第一次接触 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开发新手能有所帮助!