golang實現WebSocket的商業化使用的開發邏輯(1)
阿新 • • 發佈:2022-03-25
WebSocket是什麼
WebSocket 是一種在單個 TCP 連線上進行
全雙工
通訊的協議。其最大特點之一就是:伺服器可以主動向客戶端推送資訊,客戶端也可以主動向伺服器傳送資訊,是真正的雙向平等對話。
開發前期準備(預設已經安裝了golang
語言環境)
我這裡通過兩個庫來實現整個WebSocket的開發,這兩個庫分別是
gin
和gorilla/websocket
。這裡有兩種方法來獲取這兩個庫,其一就是用go get
,其二是使用git bash
中的git clone
拉取。我使用的是第二種方法,具體使用方法如下。
-
拉取
gorilla/websocket
到GOPATH
的src
下的github.com
git clone https://github.com/gorilla/websocket
-
拉取
gin-gonic/gin
到GOPATH
的src
下的github.com
目錄裡面git clone https://github.com/gin-gonic/gin
WebSocket 簡單使用開發(內部併發不安全,服務端server
)
開發邏輯
-
定義將
HTTP
升級成WebSocket
的全域性變數upgrade
,並預設允許跨域。var ( upgrade = &websocket.Upgrader{ // 允許跨域 CheckOrigin: func(r *http.Request) bool { return true }, } )
-
確定服務的基本結構,即確定
main
函式的結構func main(){ r := gin.Default() r.GET("/test",func(c *gin.Context){}) err := r.Run(":1234") if err != nil{ return } }
這就是用
gin
框架搭載的一個簡單HTTP
服務,這裡可以看出WebSocket就是由HTTP
進行升級得到的。現在我們只要把r.GET()
裡面的func(c *gin.Context){}
進行封裝,即可完善整個服務。 -
完善內部邏輯
func handler(c *gin.Context) { // 定義兩個變數,其一就是*websocket.Conn,其二就是error var ( conn *websocket.Conn err error ) // 賦值變數,這裡就用到了前面定義的upgrade // conn這結構體內有許多功能,可以都嘗試一下,當一般常使用: // conn.ReadMessage() // conn.WriteMessage() // conn.Close() if conn, err = upgrade.Upgrade(c.Writer, c.Request, nil); err != nil { return } // 為了防止忘記關閉WebSocket連線,使用defer defer func(conn *websocket.Conn) { if err = conn.Close(); err != nil { return } }(conn) // 這裡只處理客戶端傳什麼就返回什麼 for { // 定義資料變數 var ( msgType int // 資料型別 data []byte // 資料 errMsg error //錯誤資訊 ) // 接收資料 if msgType, data, errMsg = conn.ReadMessage(); errMsg != nil { break } // 響應資料 if errMsg = conn.WriteMessage(msgType,data); errMsg != nil{ break } } }
這裡解釋一下為什麼說這個使用為什麼內部併發不安全,因為
conn.ReadMessage()
和conn.WriteMessage()
這兩個介面是併發不安全的,它們在同一時刻不能被不同執行緒同時呼叫,否者會使服務中斷。具體情況可以在函式裡面寫過幾個goroutine
就可以深刻體會它們的這種不安全
。這就導致了一種情況做不到,就是若是想做一個心跳機制,這裡就不能再開一個goroutine
。 -
將
main
函式調整func main() { r := gin.Default() r.GET("/test", handler) err := r.Run(":1234") if err != nil { return } }
只要把
r.GET()
裡面的func(c *gin.Context){}
替換成成handler
函式即可。
完整程式碼如下
package main
import (
"github.com/gin-gonic/gin"
"golang.org/websocket"
"net/http"
)
var (
upgrade = &websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
)
func handler(c *gin.Context) {
// 定義兩個變數,其一就是*websocket.Conn,其二就是error
var (
conn *websocket.Conn
err error
)
// 賦值變數,這裡就用到了前面定義的upgrade
// conn這結構體內有許多功能,可以都嘗試一下,當一般常使用:
// conn.ReadMessage()
// conn.WriteMessage()
// conn.Close()
if conn, err = upgrade.Upgrade(c.Writer, c.Request, nil); err != nil {
return
}
// 為了防止忘記關閉WebSocket連線,使用defer
defer func(conn *websocket.Conn) {
if err = conn.Close(); err != nil {
return
}
}(conn)
// 這裡只處理客戶端傳什麼就返回什麼
for {
// 定義資料變數
var (
msgType int // 資料型別
data []byte // 資料
errMsg error //錯誤資訊
)
// 接收資料
if msgType, data, errMsg = conn.ReadMessage(); errMsg != nil {
break
}
// 響應資料
if errMsg = conn.WriteMessage(msgType,data); errMsg != nil{
break
}
}
}
func main() {
r := gin.Default()
r.GET("/test", handler)
err := r.Run(":1234")
if err != nil {
return
}
}
WebSocket 商業化使用開發 (內部併發安全,服務端server
)
邏輯結構圖
說明: