Golang 官方認可的 websocket 庫 - gorilla-websocket
推薦理由
Golang 官方標準庫實現的 websocket 在功能上有些欠缺,本次介紹的 gorilla/websocket 庫,是 Gorilla 出品的速度快、質量高,並且被廣泛使用的 websocket 庫,很好的彌補了標準庫功能上的欠缺。另外 Gorilla Web toolkit 包含多個實用的 HTTP 應用相關的工具庫,感興趣可以到官網主頁 https://www.gorillatoolkit.org 自取。
功能介紹
gorilla/websocket 庫是 RFC 6455 定義的 websocket 協議的一種實現,在數據收發方面,提供 Data Messages、Control Messages 兩類 message 粒度的讀寫 API;性能方面,提供 Buffers 和 Compression 的相關配置選項;安全方面,可通過 CheckOrigin 來控制是否支持跨域。
gorilla/websocket 庫和官方實現的對比
摘自 gorilla GitHub 主頁
使用指南
安裝
go get github.com/gorilla/websocket
基礎示例
下面以一個簡單的 echo 來說明 gorilla/websocket 庫基本使用。
client 代碼:
package main
import (
"flag"
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
var addr = flag.String("addr", "localhost:8080", "http service address")
func main() {
flag.Parse()
log.SetFlags(0)
// 用來接收命令行的終止信號
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
// 和服務端建立連接
u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
log.Printf("connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
done := make(chan struct{})
go func() {
defer close(done)
for {
// 從接收服務端message
_, 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:
// 向服務端發送message
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// 收到命令行終止信號,通過發送close message關閉連接。
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
}
}
}
server 代碼:
package main
import (
"flag"
"html/template"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var addr = flag.String("addr", "localhost:8080", "http service address")
var upgrader = websocket.Upgrader{}
func echo(w http.ResponseWriter, r *http.Request) {
// 完成和Client HTTP >>> WebSocket的協議升級
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
// 接收客戶端message
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
// 向客戶端發送message
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
}
func main() {
flag.Parse()
log.SetFlags(0)
http.HandleFunc("/echo", echo)
log.Fatal(http.ListenAndServe(*addr, nil))
}
更多示例可以參考 https://github.com/gorilla/websocket/tree/master/examples
總結
gorilla/websocket 庫是 websocket 協議的一種實現,相比標準庫的實現,封裝了協議細節,使用者關注 message 粒度的 API 即可,但需要注意 message 的讀寫 API 非併發安全,使用時注意不要多個協程併發調用。
參考資料
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://gocn.vip/topics/12349