gows是一款方便易用的Go语言websocket库,gows使用简单,能够支持大量客户端连接。具体特征如下:
go get github.com/haming123/wego/gows
package main
import (
"github.com/haming123/wego/gows"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/ws", HandlerWebSocket)
http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
t, _ := template.ParseFiles("./index.html")
t.Execute(w, user)
})
http.ListenAndServe(":8080", nil)
}
其中:
1)/index是一个web页面,在该页面中连接websocket,发送并接收websocket消息。
2)在/ws页面中进行websocket握手并升级为websocket协议。
在进行websocket握手前需要首先实现一个代表websocket连接的结构体,该结构体用于websocket事件的处理。该结构体需要实现以下接口方法:
OnClose(ws *WebSocket)
OnMessage(ws *WebSocket, opcode int, buff *ByteBuffer) error
当接收的消息时会调用OnMessage方法,消息的数据可以从buff中获取。websocket连接关闭时会调用OnClose方法。
type Client struct {
ws *gows.WebSocket
user string
}
func (c *Client) OnClose(ws *gows.WebSocket) {
log.Printf("OnClose: %s\n", c.user)
c.ws = nil
}
func (c *Client) OnMessage(ws *gows.WebSocket, opcode int, vbuff *gows.ByteBuffer) error {
log.Println("收到消息:", vbuff.GetString())
c.ws.WriteString(vbuff.GetString())
return nil
}
func HandlerWebSocket(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
ws, err := gows.Accept(w, r, nil, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
client := &Client{ws: ws, user: user}
ws.Serve(client)
}
其中的Client结构体代表客户端链接,必须实现OnMessage方法以及OnClose方法。创建Client对象后调用ws.Serve来启动消息接收循环。
func HandlerWebSocket(c *wego.WebContext) {
user := c.Param.MustString("user")
ws, err := c.AcceptWebsocket(nil, nil)
if err != nil {
c.AbortWithError(500, err)
return
}
client := &Client{ws: ws, user: user}
ws.Serve(client)
}
若要发送文本格式的消息,请调用WriteText或WriteString函数:
func (ws *WebSocket) WriteText(data []byte) error {
......
}
func (ws *WebSocket) WriteString(data string) error {
......
}
func (ws *WebSocket) WriteBinary(data []byte) error {
......
}
type Book struct {
Name string
Price float64
}
err := ws.WriteJSON(Book{"Golang", 30.2})
if err != nil {
log.Error(err)
return
}
writer := ws.NextWriter(gows.Frame_Text)
defer writer.Close()
_, err := writer.WriteString("hello")
if err != nil {
log.Error(err)
return
}
_, err := writer.WriteString(" world")
if err != nil {
log.Error(err)
return
}
package main
import (
"github.com/haming123/wego/gows"
"html/template"
"net/http"
)
func main() {
//开启发送压缩
gows.UseFlate()
//设置压缩的阈值,只有大于阈值的消息才会被压缩
gows.SetMinCompressSize(512)
http.HandleFunc("/ws", HandlerWebSocket)
http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
t, _ := template.ParseFiles("./index.html")
t.Execute(w, user)
})
http.ListenAndServe(":8080", nil)
}
gows缺省不支持跨域访问,若需要开启跨域访问,则需要自定义跨域处理函数(通过:SetOriginCheckFunc来设置)。例如:
package main
import (
"github.com/haming123/wego/gows"
"html/template"
"net/http"
)
func main() {
//允许跨域访问
gows.SetOriginCheckFunc(func(r *http.Request) bool {
return true
})
http.HandleFunc("/ws", HandlerWebSocket)
http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
t, _ := template.ParseFiles("./index.html")
t.Execute(w, user)
})
http.ListenAndServe(":8080", nil)
}
关闭websocket时需要进行关闭协商:接任一端想关闭websocket,就发一个close frame给对端,对端收到该frame后,若之前没有发过close frame,则必须回复一个close frame。
采用协商方式关闭websocket连接,请调用CloseHandshake方法:
func (ws *WebSocket) CloseHandshake(code CloseCode, text string) error {
......
}
CloseHandshake方法中的code参数为webSocket关闭状态码。webSocket关闭状态码的列表如下所示:
const (
//正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.
CloseNormalClosure CloseCode = 1000
//终端离开:可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开.
CloseGoingAway CloseCode = 1001
//协议错误:由于协议错误而中断连接.
CloseProtocolError CloseCode = 1002
//数据格式错误:由于接收到不允许的数据类型而断开连接
CloseUnsupportedData CloseCode = 1003
//保留
CloseReserved CloseCode = 1004
//没有收到预期的状态码.
CloseNoCloseRcvd CloseCode = 1005
//异常关闭:用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧).
CloseAbnormalClosure CloseCode = 1006
//由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据).
CloseInvalidPayload CloseCode = 1007
//由于收到不符合约定的数据而断开连接.
ClosePolicyViolation CloseCode = 1008
//由于收到过大的数据帧而断开连接.
CloseMessageTooBig CloseCode = 1009
//缺少扩展:客户端终止连接,因为期望一个或多个拓展, 但服务器没有.
CloseMandatoryExtension CloseCode = 1010
//内部错误:服务器终止连接,因为遇到异常
CloseInternalError CloseCode = 1011
//服务重启:服务器由于重启而断开连接.
CloseServiceRestart CloseCode = 1012
//稍后再试:服务器由于临时原因断开连接。
CloseTryAgainLater CloseCode = 1013
//错误的网关.
CloseBadGateway CloseCode = 1014
//握手错误:表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书).
CloseTLSHandshake CloseCode = 1015
)