推荐理由
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 主页
github.com/gorilla | golang.org/x/net | |
---|---|---|
RFC 6455 Features | ||
Passes Autobahn Test Suite | Yes | No |
Receive fragmented message | Yes | No, see note 1 |
Send close message | Yes | No |
Send pings and receive pongs | Yes | No |
Get the type of a received data message | Yes | Yes, see note 2 |
Other Features | ||
Compression Extensions | Experimental | No |
Read message using io.Reader | Yes | No, see note 3 |
Write message using io.WriteCloser | Yes | No, see note 3 |
Notes:
Large messages are fragmented in Chrome's new WebSocket implementation.
The application can get the type of a received data message by implementing a Codec marshalfunction.
The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. Read returns when the input buffer is full or a frame boundary is encountered. Each call to Write sends a single frame message. The Gorilla io.Reader and io.WriteCloser operate on a single WebSocket message.
使用指南
安装
go get github.com/gorilla/websocket
基础示例
下面以一个简单的echo来说明gorilla/websocket库基本使用。
client代码:
package mainimport ("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:returncase t := <-ticker.C:// 向服务端发送messageerr := 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 mainimport ("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 {// 接收客户端messagemt, message, err := c.ReadMessage()if err != nil {log.Println("read:", err)break}log.Printf("recv: %s", message)// 向客户端发送messageerr = 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非并发安全,使用时注意不要多个协程并发调用。
参考资料
https://github.com/gorilla/websocket
还想了解更多吗?
更多请查看:https://github.com/gorilla/websocket
欢迎加入我们GOLANG中国社区:https://gocn.vip/
《酷Go推荐》招募:
各位Gopher同学,最近我们社区打算推出一个类似GoCN每日新闻的新栏目《酷Go推荐》,主要是每周推荐一个库或者好的项目,然后写一点这个库使用方法或者优点之类的,这样可以真正的帮助到大家能够学习到
新的库,并且知道怎么用。
大概规则和每日新闻类似,如果报名人多的话每个人一个月轮到一次,欢迎大家报名!(报名地址:https://wj.qq.com/s2/7734329/3f51)
扫码也可以加入 GoCN 的大家族哟~