iOS 上的 WebSocket 框架 Starscream
傳統(tǒng)的網(wǎng)絡(luò)技術(shù) (也就是 Berkeley sockets) 被認(rèn)為是可靠和穩(wěn)定的浦徊。但是 Berkeley socket 在某些 web 技術(shù),比如代理和防火墻下不太好使天梧。WebSocket 出現(xiàn)于 2011 年盔性,是一種在客戶端和服務(wù)端之間建立雙向通訊的新技術(shù)。WebSocket 比起多個 HTTP 請求來說更有效率并允許長連接呢岗。
在 iOS 上使用 WebSocket 并不是那么容易交洗。iOS 和 Mac 庫 Starscream 的出現(xiàn)汉形,極大地簡化了 WebSocket 的創(chuàng)建和使用枪汪。
注:本文假設(shè)你熟悉 CocoaPods怀愧。如果你不熟悉,請參考我們的?CocoaPods 教程挫酿。
在本文中构眯,你將在一個叫做 Emoji Commuicator 的 App 中完成網(wǎng)絡(luò)編程部分。Emoji Communicator 允許你將當(dāng)前心情用一個 emoji 字符發(fā)布給所有連接到該服務(wù)的人早龟。
Emoji Communicator 原來的開發(fā)者原本打算用 HTTP 請求獲取新消息惫霸,但這個功能使用 WebSocket 顯然更合適。你將使用 Starscream 來連接后臺的 Web 服務(wù)器葱弟。
首先需要一個 Web 服務(wù)器壹店。在本文中,你會在本機上啟動一個 web 服務(wù)器芝加。這個示例的 web 服務(wù)器運行在 Node.js 下茫打,使用一小個 Javascript 文件來支持它。
當(dāng)然,首先需要安裝 Node.js老赤。如果不確定是否已經(jīng)安裝,可以在終端窗口中輸入命令:
node--version
1
如果報錯制市,請按照下列步驟下載和安裝 Node.js抬旺。否則,你會看到 Node.js 的版本號祥楣,你就可以跳過下一節(jié) Node.js 的下載开财。
在?https://nodejs.org/?下載 Node.js 的最新安裝包 (當(dāng)前 2016.9.22 的最新版本是)。下載完安裝包 (例如 node-v6.6.0.pkg)误褪,雙擊進行安裝责鳍。參考提示進行,選擇默認(rèn)選項就行了兽间。
安裝完后历葛,在終端中檢查 Node.js 是否工作正常:
node--version
1
如果你沒有看到 6.6.0 (或者你所安裝的版本),或者報錯嘀略,再次檢查安裝是否正確恤溶。
你將用到一個聊天服務(wù)器。從這里下載示例 iOS app 和 Web 服務(wù)器代碼帜羊。解壓縮 zip 包到桌面或者某個文件夾咒程。在終端中,切換到該目錄讼育,并進入 nodeapp 子目錄帐姻。
這個程序需要一個第三方模塊,需要用 Node.js 的包管理器 npm 來安裝奶段。在這個目錄中饥瓷,執(zhí)行:
npminstallwebsocket
1
輸入下列命令啟動聊天服務(wù)器:
node chat-server.js
1
你會看到類似如下輸出:
Tue Sep13201618:54:44GMT-0500(CDT) Serverislisteningonport1337
1
然后在瀏覽器 Safari 或 Chrome 中打開 frontend.html。?
輸入一個昵稱忧饭,發(fā)送一條測試消息扛伍。如果要在第二個客戶端進行測試,重新打開一個瀏覽器或標(biāo)簽頁词裤,用同一個 Url刺洒。用另一個昵稱登錄,發(fā)送一條消息吼砂;你會看到消息立即出現(xiàn)在另一個瀏覽器里逆航。
這充分說明了 WebSocket 的強大之處。每個瀏覽器都和 web 服務(wù)器有一個單獨的長連接——沒有刷新渔肩。當(dāng)消息到達因俐,服務(wù)器會自動向所有連接著的客戶端進行廣播。返回終端,你可以看到所有的聊天活動:
$nodechat-server.jsTueSep13 2016 18:54:44GMT-0500(CDT)Serverislisteningonport1337TueSep13 2016 18:55:19GMT-0500(CDT)Connectionfromoriginnull.TueSep13 2016 18:55:19GMT-0500(CDT)Connectionaccepted.TueSep13 2016 18:55:34GMT-0500(CDT)Userisknownas:Aaronwithgreencolor.TueSep13 2016 18:55:37GMT-0500(CDT)ReceivedMessagefromAaron:HelloTueSep13 2016 18:58:49GMT-0500(CDT)Connectionfromoriginnull.TueSep13 2016 18:58:49GMT-0500(CDT)Connectionaccepted.TueSep13 2016 18:58:51GMT-0500(CDT)Userisknownas:Jameswithredcolor.TueSep13 2016 18:58:55GMT-0500(CDT)ReceivedMessagefromJames:Thisisprettyslick!TueSep13 2016 18:59:03GMT-0500(CDT)ReceivedMessagefromJames: :]TueSep13 2016 18:59:27GMT-0500(CDT)Peerundefineddisconnected.
HTTP 第一次出現(xiàn)是 1991 年抹剩,它設(shè)計為一種請求/響應(yīng)式的通訊機制撑帖。Web 瀏覽器用這種機制工作良好,用戶請求 web 頁澳眷,服務(wù)器返回內(nèi)容胡嘿。但某些時候,需要有新數(shù)據(jù)時不經(jīng)過用戶請求就通知用戶——也就是钳踊,服務(wù)器推衷敌。
HTTP 協(xié)議無法很好地解決推模型。在 websocket 出現(xiàn)前拓瞪,web 服務(wù)通過一系列瀏覽器刷新機制來實現(xiàn)推模型缴罗,但效率無法讓人滿意。
webSocket 實現(xiàn)了服務(wù)端推機制祭埂。新的 web 瀏覽器全都支持 WebSocket面氓,這使得它的使用超級簡單。通過 WebSocket 能夠打開持久連接沟堡,大部分網(wǎng)絡(luò)都能輕松處理 WebSocket 連接侧但。
WebSocket 通常應(yīng)用在某些數(shù)據(jù)經(jīng)常性或頻繁改變的場景。例如 Facebook 中的 web 通知航罗、Slack 中的實時聊天禀横、交易系統(tǒng)中的變化的股票價格。
在 iOS 中使用 WebSocket 比較麻煩粥血,你必須進行大量的設(shè)置柏锄,而且內(nèi)置的 API 根本幫不上忙。這時 Starscream 出現(xiàn)了——這個小巧复亏、易于使用的庫讓你所有的煩惱不翼而飛趾娃。
打開 EmojiTransmitter.xcodeproj。在模擬器中運行程序缔御,程序很簡單抬闷,它需要用戶輸入一個昵稱,然后顯示一個界面耕突,讓用戶選擇一個 emoji 發(fā)送笤成,并顯示任何接收到的 emoji。
這個 App 還沒有完成網(wǎng)絡(luò)部分眷茁。你將使用 Starscream 來執(zhí)行所有的 WebSocket 網(wǎng)絡(luò)請求炕泳。
有許多方法可以將 Starscream 集成到你的項目。CocoaPods 和 Carthage 是兩種最常見的包管理器上祈。你兩種都可以用培遵,但本文將使用 CocoaPods浙芙。
首先,關(guān)閉打開的項目籽腕。開啟終端窗口嗡呼,將目錄切換至項目文件夾。在這個項目中已經(jīng)有一個配置了 Starscream pod 的 Podfile 文件了节仿。你可以直接安裝 pod:
pod repoupdate;pod install
1
當(dāng) CocoaPods 結(jié)束安裝晤锥,在 Xcode 8 中打開 EmojiTransmitter.xcworkspace 文件。運行程序廊宪,檢查 App 是否能夠運行。?
打開 ViewController.swift女轿,在 import UIKit 后加入:
importStarscream
1
然后箭启,在 ViewController 類的 username 屬性后增加一個屬性:
varsocket= WebSocket(url:URL(string:"ws://localhost:1337/")!, protocols: ["chat"])
1
這是創(chuàng)建 WebSocket 連接的核心。注意 URL 的歌聲蛉迹,協(xié)議是 ws 而不是 Http/https傅寡。protocols 參數(shù)指定為 chat,這取決于服務(wù)端的實現(xiàn)北救,這個協(xié)議可以被使用荐操,也可能被忽略。在本 demo 中珍策,忽略它即可托启。?
接著在 viewDidLoad 方法后加入:
deinit {socket.disconnect(forceTimeout:0)socket.delegate = nil}
1
2
3
4
當(dāng) View Controller 被銷毀時,強制關(guān)閉 WebSocket 連接攘宙。
在 Starscream 中所有的工作都放在 delegate 中進行屯耸。Starscream 也支持閉包,如果你不愿意使用委托的話蹭劈。
在 ViewController.swift疗绣,在 fileprivate 擴展后增加一個擴展:
// MARK: - WebSocketDelegateextension ViewController : WebSocketDelegate {publicfuncwebsocketDidConnect(_ socket: Starscream.WebSocket) {? }publicfuncwebsocketDidDisconnect(_ socket: Starscream.WebSocket, error: NSError?) {? }publicfuncwebsocketDidReceiveMessage(_ socket: Starscream.WebSocket, text: String) {? }publicfuncwebsocketDidReceiveData(_ socket: Starscream.WebSocket, data: Data) {? }}
這 4 個委托方法必須實現(xiàn),否則代碼無法通過編譯铺韧。
然后多矮,在 viewDidLoad 方法的 super.viewDidLoad() 后面添加:
socket.delegate = selfsocket.connect()
運行程序,輸入昵稱哈打,點擊 Next塔逃。返回 Node.js 控制臺你將看到有一個連接通知。
現(xiàn)在前酿,你已經(jīng)能夠連接到 Node.js App 了患雏,接下來是發(fā)送消息到服務(wù)器。
首先罢维,將 sendMessage(_:) 方法修改為:
func sendMessage(_message:String) {? socket.write(string:message)}
這會發(fā)送消息(本例中淹仑,就是 emoji)到 Node.js 服務(wù)器丙挽。
然后,在 websocketDidConnect(_:) 方法中加入:
socket.write(string: username)
1
這會在連接建立后發(fā)送你在第一個界面中輸入的昵稱匀借。這個服務(wù)器會將第一個接收到的消息當(dāng)做用戶名稱颜阐。?
在 websocketDidDisconnect(_:error:) 中加入:
performSegue(withIdentifier:"websocketDisconnected", sender: self)
1
無論什么原因,只要 socket 被斷開吓肋,這都會讓用戶返回到輸入昵稱界面凳怨。如果在你自己的 App 中,你應(yīng)當(dāng)在這里進行更健全的錯誤處理是鬼。
接著肤舞,在 websocketDidReceiveMessage(_:text:) 方法中:
// 1guardletdata = text.data(using: .utf16),letjsonData =try? JSONSerialization.jsonObject(with: data),letjsonDict = jsonDataas? [String: Any],letmessageType = jsonDict["type"]as? Stringelse{return}// 2ifmessageType =="message",letmessageData = jsonDict["data"]as? [String: Any],letmessageAuthor = messageData["author"]as? String,letmessageText = messageData["text"]as? String {? messageReceived(messageText, senderName: messageAuthor)}
收到的文字消息是可讀的字符串——如果是 JSON,嘗試將其轉(zhuǎn)為集合對象均蜜。代碼解釋如下:
首先將字符串轉(zhuǎn)為 NSData李剖,然后將 NSData 傳給 JSONSerialization 對象以將其轉(zhuǎn)為載體并返回一個有效的對象。最后還檢查了幾個重要的 key囤耳,并設(shè)置對應(yīng)的值篙顺。如果對象無效,直接通過 guard 語句退出充择。
過濾消息的 messageType德玫,然后將數(shù)據(jù)傳遞給 messageReceived(messageText:, senderName:) 方法。
下面是一個從 Node.js 收到的 JSON 格式的消息示例:
{? "type":"message",? "data":{? ? "time":1472513071731,? ? "text":":]",? ? "author":"iPhone Simulator",? ? "color":"orange"}}
運行 app椎麦,每當(dāng)你發(fā)送一條消息宰僧,emoji 將會用你選擇的 emoji 和昵稱刷新。返回 web 控制臺铃剔,你的 emoji 消息也會顯示撒桨。
這就是 Starscream 的使用!
在這里下載最終完成的項目键兜。
Emoji Communicator 是一個使用 WebSocket 的最簡單的例子凤类。如果你想在已經(jīng)存在的服務(wù)中使用 Starscream,你可以參考更多資料:
參考?Starscream 在 GitHub 上的項目主頁?普气。
參考?Mozilla 開發(fā)者網(wǎng)絡(luò)?上關(guān)于 WebSocket 的介紹和如何實現(xiàn) WebSocket谜疤。