如何在Go语言中使用Websockets:最佳工具与行动指南( 三 )


传输数据帧
握手成功完成后,您的应用程序可以从客户端读取数据或向客户端写入数据 。WebSocket规范定义了的一个客户机和服务器之间使用的特定帧格式 。这是框架的位模式:

如何在Go语言中使用Websockets:最佳工具与行动指南

文章插图
 
图:传输数据帧的位模式
使用以下代码对客户端有效负载进行解码:
// Recv receives data and returns a Frame func (ws *WS) Recv() (frame Frame, _ error) { frame = Frame{} head, err := ws.read(2) if err != nil { // handle error }反过来,这些代码行允许对数据进行编码:
// Send sends a Frame func (ws *WS) Send(fr Frame) error { // make a slice of bytes of length 2 data := make([]byte, 2) // Save fragmentation & opcode information in the first byte data[0] = 0x80 | fr.Opcode if fr.IsFragment { data[0] &= 0x7F } .....关闭握手当各方之一发送状态为关闭的关闭帧作为有效负载时,握手将关闭 。可选地,发送关闭帧的一方可以在有效载荷中发送关闭原因 。如果关闭是由客户端发起的,则服务器应发送相应的关闭帧作为响应 。
// Close sends a close frame and closes the TCP connectionfunc (ws *Ws) Close() error { f := Frame{} f.Opcode = 8 f.Length = 2 f.Payload = make([]byte, 2) binary.BigEndian.PutUint16(f.Payload, ws.status) if err := ws.Send(f); err != nil { return err } return ws.conn.Close()}WebSocket库列表
有几个第三方库可简化开发人员的开发工作,并极大地促进使用WebSockets 。
  • STDLIB(golang.org/x/net/websocket)
此WebSocket库是标准库的一部分 。如RFC 6455规范中所述,它为WebSocket协议实现了客户端和服务器 。它不需要安装并且有很好的官方文档 。但是,另一方面,它仍然缺少其他WebSocket库中可以找到的某些功能 。/x/net/websocket软件包中的Golang WebSocket实现不允许用户以明确的方式重用连接之间的I/O缓冲区 。
让我们检查一下STDLIB软件包的工作方式 。这是用于执行基本功能(如创建连接以及发送和接收消息)的代码示例 。
首先,要安装和使用此库,应将以下代码行添加到您的:
import "golang.org/x/net/websocket"客户端:
// create connection // schema can be ws:// or wss:// // host, port – WebSocket server conn, err := websocket.Dial("{schema}://{host}:{port}", "", op.Origin) if err != nil { // handle error } defer conn.Close() ....... // send message if err = websocket.JSON.Send(conn, {message}); err != nil { // handle error } ....... // receive message // messageType initializes some type of message message := messageType{} if err := websocket.JSON.Receive(conn, &message); err != nil { // handle error }.......服务器端:
// Initialize WebSocket handler + server mux := http.NewServeMux() mux.Handle("/", websocket.Handler(func(conn *websocket.Conn) { func() { for { // do something, receive, send, etc. } } .......// receive message // messageType initializes some type of message message := messageType{} if err := websocket.JSON.Receive(conn, &message); err != nil { // handle error } .......// send message if err := websocket.JSON.Send(conn, message); err != nil { // handle error }........
  • GORILLA
Gorilla Web工具包中的WebSocket软件包拥有WebSocket协议的完整且经过测试的实现以及稳定的软件包API 。WebSocket软件包文档齐全,易于使用 。您可以在Gorilla官方网站上找到文档 。
安装
go get github.com/gorilla/websocketExamples of codeClient side: // init // schema – can be ws:// or wss:// // host, port – WebSocket serveru := url.URL{ Scheme: {schema}, Host: {host}:{port}, Path: "/", } c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { // handle error } .......// send message err := c.WriteMessage(websocket.TextMessage, {message}) if err != nil { // handle error }.......// receive message _, message, err := c.ReadMessage() if err != nil { // handle error } .......服务器端:
// init u := websocket.Upgrader{} c, err := u.Upgrade(w, r, nil) if err != nil { // handle error } .......// receive message messageType, message, err := c.ReadMessage() if err != nil { // handle error } .......// send message err = c.WriteMessage(messageType, {message}) if err != nil { // handle error } .......
  • GOBWAS
这个微小的WebSocket封装具有强大的功能列表,例如零拷贝升级(zero-copy upgrade)和允许构建自定义数据包处理逻辑的低级API 。GOBWAS在I/O期间不需要中间做额外分配操作 。它还在wsutil软件包中提供了围绕API的高级包装API和帮助API,使开发人员可以快速使用,而无需深入研究协议的内部 。该库具有灵活的API,但这是以可用性和清晰度为代价的 。


推荐阅读