starscream

Starscream 是一个符合规范的 WebSocket (RFC 6455) 客户端库,使用 Swift 语言编写。

它的 Objective-C 版本可以在这里找到:Jetfire

特性

示例

首先要做的是导入框架。请参阅安装说明,了解如何将框架添加到您的项目中。

import Starscream

导入后,您可以打开与 WebSocket 服务器的连接。请注意,最好将 socket 设置为属性,这样它就不会在设置后立即被释放。

socket = WebSocket(url: URL(string: "ws://:8080/")!)
socket.delegate = self
socket.connect()

连接成功后,我们需要实现一些委托方法。

websocketDidConnect

当客户端连接到服务器后,websocketDidConnect 会被调用。

func websocketDidConnect(socket: WebSocketClient) {
    print("websocket is connected")
}

websocketDidDisconnect

当客户端与服务器断开连接后,websocketDidDisconnect 会被调用。

func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
	print("websocket is disconnected: \(error?.localizedDescription)")
}

websocketDidReceiveMessage

当客户端从连接中接收到文本帧时,websocketDidReceiveMessage 会被调用。

func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
	print("got some text: \(text)")
}

websocketDidReceiveData

当客户端从连接中接收到二进制帧时,websocketDidReceiveData 会被调用。

func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
	print("got some data: \(data.count)")
}

可选:websocketDidReceivePong (必需协议:WebSocketPongDelegate)

当客户端从连接中接收到 pong 响应时,websocketDidReceivePong 会被调用。您需要实现 WebSocketPongDelegate 协议并设置额外的委托,例如: socket.pongDelegate = self

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

或者您可以使用闭包。

socket = WebSocket(url: URL(string: "ws://:8080/")!)
//websocketDidConnect
socket.onConnect = {
    print("websocket is connected")
}
//websocketDidDisconnect
socket.onDisconnect = { (error: Error?) in
    print("websocket is disconnected: \(error?.localizedDescription)")
}
//websocketDidReceiveMessage
socket.onText = { (text: String) in
    print("got some text: \(text)")
}
//websocketDidReceiveData
socket.onData = { (data: Data) in
    print("got some data: \(data.count)")
}
//you could do onPong as well.
socket.connect()

还有一点:您可以通过通知监听套接字连接和断开连接。Starscream 会发布 WebsocketDidConnectNotificationWebsocketDidDisconnectNotification。您可以通过访问通知 userInfo 中的 WebsocketDisconnectionErrorKeyName 找到导致断开连接的 Error

委托方法为您提供了一种处理来自服务器数据的简单方法,但是如何发送数据呢?

写入二进制帧

writeData 方法为您提供了一种将 Data(二进制)数据发送到服务器的简单方法。

socket.write(data: data) //write some Data over the socket!

写入字符串帧

writeString 方法与 writeData 相同,但发送的是文本/字符串。

socket.write(string: "Hi Server!") //example on how to write text over the socket!

写入 ping 帧

writePing 方法与 write 相同,但发送的是 ping 控制帧。

socket.write(ping: Data()) //example on how to write a ping control frame over the socket!

写入 pong 帧

writePong 方法与 writePing 相同,但发送的是 pong 控制帧。

socket.write(pong: Data()) //example on how to write a pong control frame over the socket!

Starscream 会自动响应传入的 ping 控制帧,因此您无需手动发送 pong 帧。

但是,如果出于某种原因您需要控制此过程,则可以通过禁用 respondToPingWithPong 来关闭自动 ping 响应。

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

在大多数情况下,您不需要这样做。

断开连接

disconnect 方法的作用正如您所期望的那样,关闭套接字。

socket.disconnect()

可以通过指定超时时间(以毫秒为单位)来强制关闭套接字。超时时间为零也会立即关闭套接字,而无需等待服务器。

socket.disconnect(forceTimeout: 10, closeCode: CloseCode.normal.rawValue)

isConnected

返回套接字是否已连接。

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

自定义标头

您还可以使用您自己的自定义标头覆盖默认的 websocket 标头,如下所示

var request = URLRequest(url: URL(string: "ws://: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)

自定义 HTTP 方法

您的服务器可能在连接到 websocket 时使用不同的 HTTP 方法

var request = URLRequest(url: URL(string: "ws://:8080/")!)
request.httpMethod = "POST"
request.timeoutInterval = 5
let socket = WebSocket(request: request)

协议

如果您需要指定协议,只需将其添加到 init 中即可

//chat and superchat are the example protocols here
socket = WebSocket(url: URL(string: "ws://:8080/")!, protocols: ["chat","superchat"])
socket.delegate = self
socket.connect()

自签名 SSL

socket = WebSocket(url: URL(string: "ws://: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

SSL 证书锁定

Starscream 也支持 SSL 证书锁定。

socket = WebSocket(url: URL(string: "ws://: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 blob,或者如果您有要使用的公钥,则可以使用 SecKeyRefusePublicKeys bool 值决定是使用证书进行验证还是使用公钥。如果选择 usePublicKeys,则将自动从证书中提取公钥。

SSL 密码套件

要使用 SSL 加密连接,您需要告知 Starscream 您的服务器支持的密码套件。

socket = WebSocket(url: URL(string: "wss://: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 指向它并查看结果。

压缩扩展

Starscream 支持压缩扩展 (RFC 7692)。默认情况下启用压缩,但是只有当服务器也支持压缩时才会使用压缩。您可以通过 .enableCompression 属性启用或禁用压缩

socket = WebSocket(url: URL(string: "ws://:8080/")!)
socket.enableCompression = false

如果您的应用程序正在传输已压缩、随机或其他不可压缩的数据,则应禁用压缩。

自定义队列

可以指定在调用委托方法时使用的自定义队列。默认情况下使用 DispatchQueue.main,因此所有委托方法调用都在主线程上运行。重要的是要注意,所有 WebSocket 处理都在后台线程上完成,只有在修改队列时才会更改委托方法调用。实际处理始终在后台线程上进行,不会暂停您的应用程序。

socket = WebSocket(url: URL(string: "ws://:8080/")!, protocols: ["chat","superchat"])
//create a custom queue
socket.callbackQueue = DispatchQueue(label: "com.vluxe.starscream.myapp")

示例项目

查看 examples 目录中的 SimpleTest 项目,了解如何设置与 WebSocket 服务器的简单连接。

要求

Starscream 适用于 iOS 7/OSX 10.9 或更高版本。建议使用 iOS 8/10.10 或更高版本以获得 CocoaPods/框架支持。要在目标为 iOS 7 的项目中使用 Starscream,您必须将所有 Swift 文件直接包含在您的项目中。

安装

CocoaPods

查看 cocoapods.org 上的 Get Started 选项卡。

要在您的项目中使用 Starscream,请将以下 'Podfile' 添加到您的项目

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!

pod 'Starscream', '~> 3.0.2'

然后运行

pod install

Carthage

查看 Carthage 文档,了解如何添加安装。Starscream 框架已经使用共享方案进行了设置。

Carthage 安装

您可以使用 Homebrew 使用以下命令安装 Carthage

$ brew update
$ brew install carthage

要使用 Carthage 将 Starscream 集成到您的 Xcode 项目中,请在您的 Cartfile 中指定它

github "daltoniam/Starscream" >= 3.0.2

Rogue

首先查看 安装文档,了解如何安装 Rogue。

要安装 Starscream,请在您创建 rogue 文件的目录中运行以下命令。

rogue add https://github.com/daltoniam/Starscream

接下来,打开 libs 文件夹并将 Starscream.xcodeproj 添加到您的 Xcode 项目。完成后,在您的 “Build Phases” 中,将 Starscream.framework 添加到您的 “Link Binary with Libraries” 阶段。确保将 libs 文件夹添加到您的 .gitignore 文件中。

Swift Package Manager

Swift Package Manager 是一个用于自动化 Swift 代码分发的工具,并已集成到 swift 编译器中。

一旦您设置了 Swift 包,将 Starscream 添加为依赖项就像将其添加到 Package.swiftdependencies 值一样简单。

dependencies: [
    .Package(url: "https://github.com/daltoniam/Starscream.git", majorVersion: 3)
]

其他

只需获取框架(通过 git submodule 或其他包管理器)。

Starscream.xcodeproj 添加到您的 Xcode 项目。完成后,在您的 “Build Phases” 中,将 Starscream.framework 添加到您的 “Link Binary with Libraries” 阶段。

添加复制框架阶段

如果您在 OSX 应用程序或物理 iOS 设备上运行此程序,则需要确保将 Starscream.framework 添加到您的应用程序包中。为此,在 Xcode 中,通过单击蓝色项目图标并选择侧边栏中 “Targets” 标题下的应用程序目标,导航到目标配置窗口。在该窗口顶部的选项卡栏中,打开 “Build Phases” 面板。展开 “Link Binary with Libraries” 组,并添加 Starscream.framework。单击面板左上角的 + 按钮,然后选择 “New Copy Files Phase”。将这个新阶段重命名为 “Copy Frameworks”,将 “Destination” 设置为 “Frameworks”,并分别添加 Starscream.framework

WebSocketAdvancedDelegate

高级委托的行为与更简单的委托类似,但提供有关连接和传入帧的一些其他信息。

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 upgrade 请求和响应返回时被调用。

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.")
}

已知问题

TODOs

许可证

Starscream 在 Apache v2 许可证下获得许可。

联系方式

Dalton Cherry

Austin Cherry