golang開發(fā)?gorilla?websocket的使用示例詳解
很多APP都需要主動向用戶推送消息,這就需要用到長連接的服務(wù),即我們通常提到的websocket,同樣也是使用socket服務(wù),通信協(xié)議是基本類似的,在go中用的最多的、也是最簡單的socket服務(wù)就是gorilla/websocket,它有21.1K的star,足以說明它的受歡迎程度, 它的github地址是 https://github.com/gorilla/websocket,我們的長連接服務(wù)也是通過gorilla/websocket改造出來的。
websocket的簡單使用
我們使用的版本是1.3.0,首先下載websocket
go get github.com/gorilla/websocket@v1.3.0
把websocket/examples/echo下面的 client.go server.go 現(xiàn)在下來拷貝到項目里面。
https://github.com/gorilla/websocket/blob/v1.3.0/examples/echo/server.go
https://github.com/gorilla/websocket/blob/v1.3.0/examples/echo/client.go
在一個終端執(zhí)行 websocket 服務(wù)
go run server.go
recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889 recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605 recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325 recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866 recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108 recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310 recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266
再打開一個終端執(zhí)行 go run client.go,充當(dāng)客戶端
connecting to ws://localhost:8080/echo recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889 recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605 recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325 recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866 recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108 recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310 recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266
我們看看這個簡單的例子。
client.go
go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Printf("recv: %s", message) } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-done: return case t := <-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) if err != nil { log.Println("write:", err) return } case <-interrupt: log.Println("interrupt") // Cleanly close the connection by sending a close message and then // waiting (with timeout) for the server to close the connection. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("write close:", err) return } select { case <-done: case <-time.After(time.Second): } return } }
go func() 的 c.ReadMessage 不停的從socket里面讀取數(shù)據(jù)并且打印。
for 循環(huán)不停的從1秒的定時器里面讀取時間,寫到socket
server.go
for { mt, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) break } log.Printf("recv: %s", message) err = c.WriteMessage(mt, message) if err != nil { log.Println("write:", err) break } }
for c.ReadMessage 循環(huán)不停的從 socket讀取數(shù)據(jù),把數(shù)據(jù)打印之后,又寫給客戶端。
這是大致的websocket 客戶端與服務(wù)端通信的簡單例子。
改成自定義的協(xié)議
我們使用二進制數(shù)據(jù)流,自定義的協(xié)議是這樣的,
先是無符號的 uint 占4個字節(jié),表示行為邏輯,比如111-獲取信息, 110- 加好友等等
后面是具體的數(shù)據(jù),跟HTTP請求的GET或者POST參數(shù)類似,具體數(shù)據(jù)格式定義好就行,比如可以使用JSON數(shù)據(jù)、可以使用RPC定義好的數(shù)據(jù)格式
修改完之后 client.go 代碼是這樣的
for { select { case <-done: return case <-ticker.C: buf := bytes.NewBuffer([]byte{}) binary.Write(buf, binary.BigEndian, uint32(110)) binary.Write(buf, binary.BigEndian, []byte("我們都好")) err := c.WriteMessage(websocket.BinaryMessage, buf.Bytes()) if err != nil { log.Println("write:", err) return } case <-interrupt: log.Println("interrupt") // Cleanly close the connection by sending a close message and then // waiting (with timeout) for the server to close the connection. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("write close:", err) return } select { case <-done: case <-time.After(time.Second): } return } }
主要是這個
buf := bytes.NewBuffer([]byte{}) binary.Write(buf, binary.BigEndian, uint32(110)) binary.Write(buf, binary.BigEndian, []byte("我們都好"))
創(chuàng)建一個bytes Buffer
寫入一個uint32,占4個字節(jié),表示行為邏輯
寫入行為邏輯具體的數(shù)據(jù)
以上采用大端通信
修改之后的 server.go
for { mt, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) break } log.Println("messagetype:%d", mt) log.Println("messagelen:%d", len(message)) log.Println("messagetype:%d", binary.BigEndian.Uint32(message[0:4])) log.Println("recv: %s", string(message[4:])) err = c.WriteMessage(mt, message) if err != nil { log.Println("write:", err) break } }
mt websocket 類型
TextMessage = 1 文本類型傳傳輸
BinaryMessage = 2 字節(jié)類型傳輸
從socket里面獲取到message之后
先取前4個字節(jié),表示邏輯行為
再取剩余的字節(jié),表示行為邏輯需要的參數(shù)
我們重新執(zhí)行一下,server.go 和 client.go
go run client.go connecting to ws://localhost:8080/echo recv: n我們都好 recv: n我們都好 go run server.go messagetype:%d 2 messagelen:%d 16 messagetype:%d 110 recv: %s 我們都好
messagetype=2表示二進制通信
message長度是16,前四個字節(jié)是無符號整形,四個漢字占12個字節(jié),一共16個字節(jié),無符號uint是110表示加好友。
這就是一個簡單自定義協(xié)議的socket服務(wù)。
如果有需要登錄鑒權(quán)的話,在server.go中可以從r *http.Request 獲取header或者cookie,進行登錄鑒權(quán)驗證。
生產(chǎn)的部署
因為是 websocket 協(xié)議,如果有代理服務(wù)器的話,需要在各代理服務(wù)器上的Nginx做協(xié)議升級,將HTTP 升級為 websocket ,比如下面的代理服務(wù)器。
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; location /serv/ { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_connect_timeout 3; proxy_redirect off; proxy_read_timeout 3600; proxy_send_timeout 3600; proxy_pass http://push_web/serv/; } }
到此這篇關(guān)于golang開發(fā) gorilla websocket的使用示例詳解的文章就介紹到這了,更多相關(guān)golang開發(fā) gorilla websocket內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang利用redis和gin實現(xiàn)保存登錄狀態(tài)校驗登錄功能
這篇文章主要介紹了golang利用redis和gin實現(xiàn)保存登錄狀態(tài)校驗登錄功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01Go實現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼
本文主要介紹了Go實現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07基于Go+OpenCV實現(xiàn)人臉識別功能的詳細(xì)示例
OpenCV是一個強大的計算機視覺庫,提供了豐富的圖像處理和計算機視覺算法,本文將向你介紹在Mac上安裝OpenCV的步驟,并演示如何使用Go的OpenCV綁定庫進行人臉識別,需要的朋友可以參考下2023-07-07Golang中基礎(chǔ)的命令行模塊urfave/cli的用法說明
這篇文章主要介紹了Golang中基礎(chǔ)的命令行模塊urfave/cli的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12詳解Golang中Context的三個常見應(yīng)用場景
Golang?context主要用于定義超時取消,取消后續(xù)操作,在不同操作中傳遞值。本文通過簡單易懂的示例進行說明,感興趣的可以了解一下2022-12-12Go條件控制語句詳解(if-else、switch和select)
條件語句用于檢查一個條件是否為真,并根據(jù)條件的真假來決定是否執(zhí)行相應(yīng)的代碼,下面這篇文章主要給大家介紹了關(guān)于Go條件控制語句(if-else、switch和select)的相關(guān)資料,需要的朋友可以參考下2024-03-03