用 Go 編寫一個簡單的 WebSocket 推送服務 本文中代碼可以在 "github.com/alfred zhong/wserver" 獲取。 背景 最近拿到需求要在網頁上展示報警信息。以往報警信息都是通過簡訊,微信和 App 推送給用戶的,現在要讓登錄用戶在網頁端也能實時接收到報警推送。 依 ...
用 Go 編寫一個簡單的 WebSocket 推送服務
本文中代碼可以在 github.com/alfred-zhong/wserver 獲取。
背景
最近拿到需求要在網頁上展示報警信息。以往報警信息都是通過簡訊,微信和 App 推送給用戶的,現在要讓登錄用戶在網頁端也能實時接收到報警推送。
依稀記得以前工作的時候遇到過類似的需求。因為以前的瀏覽器標準比較陳舊,並且那時用 Java 較多,所以那時候解決這個問題就用了 Comet4J。具體的原理就是長輪詢,長鏈接。但現在畢竟 html5 流行開來了,IE 都被 Edge 接替了,再用以前這種技術就顯得過時。
很早以前就聽過 WebSocket 的大名,但因為那時很多用戶的瀏覽器還不支持,所以對這個技術也就是淺嘗輒止,沒有太深入研究過。現在趁著項目需要,就來稍微深入瞭解一下。
websocket 簡介
以往瀏覽器要獲取服務端數據,都是通過發送 HTTP 請求,然後等待服務端回應的。也就是說瀏覽器端一直是整個請求的發起者,只有它主動,才能獲取到數據。而要讓瀏覽器一側能夠獲取到服務端的實時數據,就需要不停地向服務端發起請求。雖然大多數情況下並沒有獲取到實際數據,但這大大增加了網路壓力,對於服務端來說壓力也直線上升。
後來我們學會了使用長連接 + 長輪詢的方式。換句話說,也就是延長 HTTP 請求的存在時間,儘量保持 HTTP 連接。雖然這在一定程度上降低了不少壓力,但仍然需要不停地進行輪詢,也做不到真正的實時性。(借用一張圖)
隨著 HTML5 的到來,WebSocket 在 2011 年被定為標準(詳情請參見 RFC 6455)。
借用 《Go Web 編程》的話。WebSocket 採用了一些特殊的報頭,使得瀏覽器和伺服器只需要做一個握手的動作,就可以在瀏覽器和伺服器之間建立一條連接通道。且此連接會保持在活動狀態,你可以使用 JavaScript 來向連接寫入或從中接收數據,就像在使用一個常規的 TCP Socket 一樣。它解決了 Web 實時化的問題。
由於 WebSocket 是全雙工通信,所以當建立了 WebSocket 連接之後,接下來的通信就類似於傳統的 TCP 通信了。客戶端和服務端可以相互發送數據,不再有實時性的問題。
開發包的選擇
在 Go 官方的 SDK 中,並不包含對 WebSocket 的支持,所以必須使用第三方庫。
要使用 Golang 開發 WebSocket,選擇基本就在 x/net/websocket 和 gorilla/websocket 之間。《Go Web 編程》一書中的例子使用了 x/net/websocket
作為開發包,而且貌似它也更加官方且正式。而實際根據我在網上查詢得到的反饋看來,並非如此。x/net/websocket
貌似 Bug 較多,且較為不穩定,問題解決也並不及時。相比之下,gorilla/websocket
則更加優秀。
還有對於 Gorilla web toolkit 組織的貢獻,必須予以感謝。