最近在写一个需要前后端保持通信的服务。前端要能及时感知后端数据的变化,后端要及时处理前端发过来的指令。这种服务就需要用到websocket了。
以前在写websocket相关的程序时,一直在用gorilla/websocket这个库,这个库事实上已经成为了go语言开发websocket应用的基础库了,不过它提供的功能比较有限,各种基本的功能,心跳等都要自己补充完善。最近这个库因找不到接手的维护人员而停止维护了。
这一两年有很多go语言的代码库停止维护了,这算是go语言相比其他语言的一个比较大的风险吧,大量go语言代码库是由为爱发电的开发者自行维护的,很多使用量非常高的库其核心开发人员只有一两个人。这些库的代码质量,维护周期都由其开发者来决定,没有回报的事情往往是做不长远的。
因为自己并不是很熟悉websocket,之前写websocket的程序时都是把例子改一改实现自己想要的功能就结束了。这次在编写调试的过程中发现了很多问题,gorilla/websocket
太基础了不能满足我的需求,这促使我寻找更易用的websocket库。
我找到了两个比较好用的库,一个是melody,另一个是GoWebsocket。它们目前都还保持着更新,都是基于gorilla/websocket
库的更上层的库,其中melody
是服务端的库,GoWebsocket
是客户端的库。
melody
库有以下几个特性:
- Clear and easy interface similar to net/http or Gin.
- A simple way to broadcast to all or selected connected sessions.
- Message buffers making concurrent writing safe.
- Automatic handling of sending ping/pong heartbeats that timeout broken sessions.
- Store data on sessions.
它最吸引我的地方在于它对websocket的一些基本的操作做了封装。可以很好地与gin集成,支持广播,支持自动收发心跳,支持通过session来存储不同连接的数据。
GoWebsocket
库有以下几个特性:
- Support for emitting and receiving text and binary data
- Data compression
- Concurrency control
- Proxy support
- Setting request headers
- Subprotocols support
- SSL verification enable/disable
通过它可以很方便地用go写出websocket客户端。
这里我简单介绍一下用melody写服务端,GoWebsocket写客户端,实现一个交互式的命令处理程序(就是客户端发一个指令,服务端返回相应的回复结果)
服务端:
package main
import (
"github.com/gin-gonic/gin"
"github.com/olahol/melody"
"time"
)
func main() {
r := gin.Default()
m := melody.New()
r.GET("/ws", func(c *gin.Context) {
m.HandleRequest(c.Writer, c.Request)
})
m.HandleMessage(func(s *melody.Session, msg []byte) {
switch string(msg) {
case "hello":
s.Write([]byte("hi"))
case "time":
s.Write([]byte(time.Now().String()))
case "exit":
s.Write([]byte("Bye bye!"))
s.Close()
default:
s.Write([]byte("Unknown Message"))
}
})
r.Run(":5001")
}
客户端
package main
import (
"fmt"
"github.com/sacOO7/gowebsocket"
"log"
"os"
"os/signal"
)
func main() {
exit := make(chan struct{}, 1)
socket := gowebsocket.New("ws://127.0.0.1:5001/ws")
socket.OnConnected = func(socket gowebsocket.Socket) {
log.Println("Connected to server")
}
socket.OnTextMessage = func(message string, socket gowebsocket.Socket) {
log.Println("Recieved message: " + message)
}
socket.OnDisconnected = func(err error, socket gowebsocket.Socket) {
exit <- struct{}{}
return
}
socket.Connect()
var msg string
for {
select {
case <-exit:
return
default:
if msg != "exit" {
fmt.Scanln(&msg)
socket.SendText(msg)
}
}
}
}
代码比较简单,服务端采用gin框架,当/ws
有连接进入后,就由melody进行处理,简单地根据传入的消息返回相应的结果给客户端。
江达小记