IOS Websocket (一) Starscream实现Websocket通讯

@TOC

1.Starscream 简介

  1. Conforms to all of the base Autobahn test suite.
  2. Nonblocking. Everything happens in the background, thanks to GCD.
  3. TLS/WSS support.
  4. Compression Extensions support (RFC 7692)
  5. Simple concise codebase at just a few hundred LOC.
  • 什么是websocket:

WebSocket protocolHTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。
WebSocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

  1. HTTP 第一次出现是 1991 年,它设计为一种请求/响应式的通讯机制。Web 浏览器用这种机制工作良好,用户请求 web 页,服务器返回内容。但某些时候,需要有新数据时不经过用户请求就通知用户——也就是,服务器推。
  2. HTTP 协议无法很好地解决推模型。在 websocket 出现前,web 服务通过一系列浏览器刷新机制来实现推模型,但效率无法让人满意。
  3. webSocket 实现了服务端推机制。新的 web 浏览器全都支持 WebSocket,这使得它的使用超级简单。通过 WebSocket 能够打开持久连接,大部分网络都能轻松处理 WebSocket 连接。
  4. WebSocket 通常应用在某些数据经常性或频繁改变的场景。例如 Facebook 中的 web 通知、Slack 中的实时聊天、交易系统中的变化的股票价格
  • socket通讯过程:


    socket连接过程
  • 集成Websocket:

开发中推荐使用Starscream框架。通过pod 方式导入:

 pod 'Starscream'
  • Starscream 使用swift版本为4.2

2.Starscream 使用

2.1 Starscream基本使用

 import UIKit
    import Starscream
   @objc public protocol DSWebSocketDelegate: NSObjectProtocol{
    /**websocket 连接成功*/
    optional func websocketDidConnect(sock: DSWebSocket)
    /**websocket 连接失败*/
    optional  func websocketDidDisconnect(socket: DSWebSocket, error: NSError?)
    /**websocket 接受文字信息*/
    func websocketDidReceiveMessage(socket: DSWebSocket, text: String)
    / **websocket 接受二进制信息*/
    optional  func  websocketDidReceiveData(socket: DSWebSocket, data: NSData)
    }
  public class DSWebSocket: NSObject,WebSocketDelegate {
    var socket:WebSocket!
    weak var webSocketDelegate: DSWebSocketDelegate?
    //单例
    class func sharedInstance() -> DSWebSocket
    {
        return manger
    }
    static let manger: DSWebSocket = {
        return DSWebSocket()
    }()

    //MARK:- 链接服务器
  func connectSever(){
    socket = WebSocket(url: NSURL(string: 你的URL网址如:ws://192.168.3.209:8080/shop))
    socket.delegate = self
    socket.connect()
   }

   //发送文字消息
   func sendBrandStr(brandID:String){
    socket.writeString(brandID))
  }
  //MARK:- 关闭消息
  func disconnect(){
      socket.disconnect()
  }

  //MARK: - WebSocketDelegate
  //客户端连接到服务器时,websocketDidConnect将被调用。
  public func websocketDidConnect(socket: WebSocket){
      debugPrint("连接成功了: \(error?.localizedDescription)")
      webSocketDelegate?.websocketDidConnect!(self)
  }
  //客户端与服务器断开连接后,将立即调用 websocketDidDisconnect。
  public func websocketDidDisconnect(socket: WebSocket, error: NSError?){
    debugPrint("连接失败了: \(error?.localizedDescription)")
    webSocketDelegate?.websocketDidDisconnect!(self, error: error)
  }
  //当客户端从连接获取一个文本框时,调用 websocketDidReceiveMessage。
  //注:一般返回的都是字符串
  public func websocketDidReceiveMessage(socket: WebSocket, text: String){
   debugPrint("接受到消息了: \(error?.localizedDescription)")
        webSocketDelegate?.websocketDidReceiveMessage!(self, text: text)
  }
  public func websocketDidReceiveData(socket: WebSocket, data: NSData){
    debugPrint("data数据")
    webSocketDelegate?.websocketDidReceiveData!(self, data: data)
      }
   }
  • 编写一个pong框架
    writePong方法与writePing相同,但发送一个pong控制帧。
socket.write(pong: Data()) //example on how to write a pong control frame over the socket!

Starscream会自动响应传入的ping 控制帧,这样你就不需要手动发送 pong。

但是,如果出于某些原因需要控制这个 prosses,你可以通过禁用 respondToPingWithPong 来关闭自动 ping 响应。

socket.respondToPingWithPong=false//Do not automaticaly respond to incoming pings with pongs.

当客户端从连接获得一个pong响应时,调用 websocketDidReceivePong。 你需要实现WebSocketPongDelegate协议并设置一个额外的委托,例如: socket.pongDelegate = self

funcwebsocketDidReceivePong(socket: WebSocketClient, data: Data?) {
 print("Got pong! Maybe some data: (data?.count)")
}

2.2 Starscream高阶使用

2.2.1 判断是否连接

if socket.isConnected {
 // do cool stuff.
 }

2.2.2 自定义头文件

  • 你可以使用自己自定义的web socket标头覆盖默认的web socket标头,如下所示:
var request = URLRequest(url: URL(string: "ws://localhost:8080/")!)
request.timeoutInterval = 5
request.setValue("someother protocols", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("14", forHTTPHeaderField: "Sec-WebSocket-Version")
request.setValue("Everything is Awesome!", forHTTPHeaderField: "My-Awesome-Header")
let socket = WebSocket(request: request)

2.2.3 自定义HTTP方法

  • 你的服务器在连接到 web socket时可能会使用不同的HTTP方法:
var request = URLRequest(url: URL(string: "ws://localhost:8080/")!)
request.httpMethod = "POST"
request.timeoutInterval = 5
let socket = WebSocket(request: request)

2.2.4 协议

  • 如果需要指定协议,简单地将它的添加到 init:
//chat and superchat are the example protocols here
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
socket.delegate = self
socket.connect()

2.2.5 自签名 SSL

socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])

//set this if you want to ignore SSL cert validation, so a self signed SSL certificate can be used.
socket.disableSSLCertValidation = true

2.2.5.1 SSL引脚

  • Starscream还支持SSL固定。
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
let data = ... //load your certificate from disk
socket.security = SSLSecurity(certs: [SSLCert(data: data)], usePublicKeys: true)
//socket.security = SSLSecurity() //uses the .cer files in your app's bundle

你可以加载证书的Data 小区,否则你可以使用 SecKeyRef,如果你想要使用 public 键。 usePublicKeys bool是使用证书进行验证还是使用 public 键。 如果选择 usePublicKeys,将自动从证书中提取 public 密钥。

2.2.5.2 SSL密码套件

  • 要使用SSL加密连接,你需要告诉小红你的服务器支持的密码套件。
socket = WebSocket(url: URL(string: "wss://localhost:8080/")!, protocols: ["chat","superchat"])

// Set enabled cipher suites to AES 256 and AES 128
socket.enabledSSLCipherSuites = [TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256] 

如果你不知道服务器支持哪些密码套件可以查看:SSL Labs

2.2.6 压缩扩展

  • Starscream支持压缩扩展( RFC 7692 )。 默认情况下,压缩是启用的,但是只有当服务器支持压缩时才会使用压缩。 你可以通过 .enableCompression 属性启用或者禁用压缩:
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!)
socket.enableCompression = false
  • 如果应用程序正在传输已经压缩。随机或者其他uncompressable数据,则应禁用压缩。

2.2.7 自定义队列

  • 调用委托方法时可以指定自定义队列。 默认使用 DispatchQueue.main,因此使所有委托方法调用都在主线程上运行。 重要的是要注意,所有 web socket处理都是在后台线程上完成的,只有修改队列时才更改委托方法。 实际的处理总是在后台线程上,不会暂停你的应用程序。
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
//create a custom queue
socket.callbackQueue = DispatchQueue(label: "com.vluxe.starscream.myapp")

2.2.8 高级代理

socket.advancedDelegate = self
  • websocketDidReceiveMessage
func websocketDidReceiveMessage(socket: WebSocketClient, text: String, response: WebSocket.WSResponse) {
    print("got some text: \(text)")
    print("First frame for this message arrived on \(response.firstFrame)")
}
  • websocketDidReceiveData
func websocketDidReceiveData(socket: WebSocketClient, data: Date, response: WebSocket.WSResponse) {
    print("got some data it long: \(data.count)")
    print("A total of \(response.frameCount) frames were used to send this data")
}
  • websocketHttpUpgrade

当发送HTTP升级请求后,会返回下面回调

func  websocketHttpUpgrade(socket: WebSocketClient, request: CFHTTPMessage) {
    print("the http request was sent we can check the raw http if we need to")
}

func  websocketHttpUpgrade(socket: WebSocketClient, response: CFHTTPMessage) {
    print("the http response has returned.")
}

3.Starscream 使用Demo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容