1.websocket 簡介
以往瀏覽器要擷取服務端資料,都是通過發送 HTTP 要求,然後等待服務端回應的。也就是說瀏覽器端一直是整個請求的發起者,只有它主動,才能擷取到資料。而要讓瀏覽器一側能夠擷取到服務端的即時資料,就需要不停地向服務端發起請求。雖然大多數情況下並沒有擷取到實際資料,但這大大增加了網路壓力,對於服務端來說壓力也直線上升。
image.png
由於 WebSocket 是全雙工系統通訊,所以當建立了 WebSocket 串連之後,接下來的通訊就類似於傳統的 TCP 通訊了。用戶端和服務端可以相互發送資料,不再有即時性的問題。
image.png
image.png
2.開發包的選擇
在 Go 官方的 SDK 中,並不包含對 WebSocket 的支援,所以必須使用第三方庫。
要使用 Golang 開發 WebSocket,選擇基本就在 x/net/websocket 和 gorilla/websocket 之間。《Go Web 編程》一書中的例子使用了 x/net/websocket
作為開發包,而且貌似它也更加官方且正式。而實際根據我在網上查詢得到的反饋看來,並非如此。x/net/websocket
貌似 Bug 較多,且較為不穩定,問題解決也並不及時。相比之下,gorilla/websocket
則更加優秀。
下載連結及手冊
3.推送服務實現
server 啟動以後會註冊兩個 Handler。
websocketHandler 用於提供瀏覽器端發送 Upgrade 請求並升級為 WebSocket 串連。 pushHandler 用於提供外部推送端發送推送資料的請求。
3-1.go代碼的簡單實現
package mainimport ( "net/http" "log" "github.com/gorilla/websocket")var ( upgrader = websocket.Upgrader { // 讀取儲存空間大小 ReadBufferSize:1024, // 寫入儲存空間大小 WriteBufferSize:1024, // 允許跨域 CheckOrigin: func(r *http.Request) bool { return true }, })func wsHandler(w http.ResponseWriter, r *http.Request) { var ( wbsCon *websocket.Conn err error data []byte ) // 完成http應答,在httpheader中放下如下參數 if wbsCon, err = upgrader.Upgrade(w, r, nil);err != nil { return // 擷取串連失敗直接返回 } for { // 只能發送Text, Binary 類型的資料,底線意思是忽略這個變數. if _, data, err = wbsCon.ReadMessage();err != nil { goto ERR // 跳轉到關閉串連 } if err = wbsCon.WriteMessage(websocket.TextMessage, data); err != nil { goto ERR // 發送訊息失敗,關閉串連 } } ERR: // 關閉串連 wbsCon.Close()}func main() { // 當有請求訪問ws時,執行此回調方法 http.HandleFunc("/ws",wsHandler) // 監聽127.0.0.1:7777 err := http.ListenAndServe("0.0.0.0:7777", nil) if err != nil { log.Fatal("ListenAndServe", err.Error()) }}
3-2.前端代碼
<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <style> *{ margin:0px; padding:0px; } </style></head><body><div style="margin-left:400px"> <h3>群聊天室</h3> <div style="border:1px solid;width: 600px;height: 300px;"> <div id="msgArea" style="width:100%;height: 100%;text-align:start;resize: none;font-family: 微軟雅黑;font-size: 20px;overflow-y: scroll"></div> </div> <div style="border:1px solid;width: 600px;height: 100px;"> <div style="width:100%;height: 100%;"> <textarea id="userMsg" style="width:100%;height: 100%;text-align:start;resize: none;font-family: 微軟雅黑;font-size: 20px;"></textarea> </div> </div> <div style="border:1px solid;width: 600px;height: 25px;"> <button style="float: right;" onclick="sendMsg()">發送</button> </div></div></body></html><script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script><script> var ws; $(function(){ link(); }) function link () { ws = new WebSocket("ws://127.0.0.1:7777/ws");//串連伺服器 ws.onopen = function(event){ console.log(event); alert('串連了'); }; ws.onmessage = function (event) { var date = new Date(); var msg = "<p>"+date.toLocaleString()+"</p>"+"<p>"+event.data+"</p>"; $("#msgArea").append(msg); } ws.onclose = function(event){alert("已經與伺服器中斷連線\r\n當前串連狀態:"+this.readyState);}; ws.onerror = function(event){alert("WebSocket異常!");}; } function sendMsg(){ var msg = $("#userMsg").val(); ws.send(msg); }</script>
3-3. 結果分析
啟動並執行結果
image.png
互動的過程
1.request請求時,要求將協議升級為websocket 參數
2.response返回時,如果成功則返回websocket 參數
image.png
資料傳送形式是把資料拆成多個frame進行發送和接收,這個不用我們關心。
image.png
image.png
4.第三方資源
https://www.imooc.com/video/17599
https://www.cnblogs.com/snowInPluto/p/8688453.html
5.PHP前沿學習群: 257948349 go也收