Go中的WebSocket:gorilla/websocket库与标准实现

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Go(Golang)WebSocket库:gorilla/websocket与标准net/http



WebSocket是一种协议,通过单个长久的TCP连接在客户端和服务器之间提供全双工通信。与传统的HTTP不同,建立连接后,数据可以在任何时刻双向传输,无需客户端持续发起请求。这是聊天、实时通知、在线游戏和交易平台的理想解决方案。



在Go(Golang)生态系统中,有几种处理WebSocket的方式。最流行且经过时间考验的是gorilla/websocket库。然而,从Go 1.22开始,可以使用标准包net/http实现基本的WebSocket服务器,而无需第三方依赖。本文将详细分析这两种方法。



安装gorilla/websocket库



要开始使用gorilla/websocket,请通过go get安装:



go get github.com/gorilla/websocket


该库提供了方便的API,用于创建服务器端和客户端部分。它处理握手、消息帧、支持压缩以及自动ping/pong。



基于gorilla/websocket的WebSocket服务器



来看一个简单的回声服务器示例。客户端发送消息,服务器将其返回:



package main

import ( "log" "net/http" "github.com/gorilla/websocket")

var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true // 允许任何来源(用于开发) },}

func echoHandler(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Print("升级失败:", err) return } defer conn.Close()

for { messageType, message, err := conn.ReadMessage() if err != nil { log.Println("读取错误:", err) break } log.Printf("收到: %s", message)

if err := conn.WriteMessage(messageType, message); err != nil { log.Println("写入错误:", err) break } }}

func main() { http.HandleFunc("/echo", echoHandler) log.Fatal(http.ListenAndServe(":8080", nil))}


这里的Upgrader将普通的HTTP请求转换为WebSocket连接。CheckOrigin函数控制允许连接的域名。在生产环境中,建议检查特定的来源。



基于gorilla/websocket的WebSocket客户端



连接我们服务器并发送消息的客户端示例:



package main

import ( "log" "os" "os/signal" "time" "github.com/gorilla/websocket")

func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt)

url := "ws://localhost:8080/echo" c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { log.Fatal("拨号:", err) } defer c.Close()

done := make(chan struct{})

// 用于读取响应的协程 go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("读取:", err) return } log.Printf("接收: %s", message) } }()

// 发送消息 ticker := time.NewTicker(time.Second) defer ticker.Stop()

for { select { case <-done: return case t := <-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) if err != nil { log.Println("写入:", err) return } case <-interrupt: log

推荐