Go语言如何实现WebSocket通信_WebSocket基础用法

Go标准库不支持WebSocket,需用gorilla/websocket;服务端用Upgrader升级连接后读写消息,客户端需手动拨号并处理重连与超时。

go语言如何实现websocket通信_websocket基础用法

Go标准库不支持WebSocket,必须用第三方包

Go语言原生net/http包只提供HTTP协议支持,没有内置WebSocket实现。直接调用http.ResponseWriterWrite方法或试图升级连接会失败,因为缺少WebSocket握手、帧解析和心跳等关键逻辑。

主流选择是gorilla/websocket——它稳定、文档清晰、被大量生产项目验证。别用已归档的golang.org/x/net/websocket,也不建议从零手写WebSocket帧处理。

服务端:用gorilla/websocket建立连接并读写消息

核心是websocket.Upgrader升级HTTP请求,再用*websocket.Conn收发数据。注意升级过程必须在HTTP handler中完成,且不能有任何前置WriteHeader修改(否则触发http: multiple response.WriteHeader calls错误)。

  • Upgrader.CheckOrigin默认拒绝跨域请求,开发时可临时设为func(r *http.Request) bool { return true },生产环境应校验Origin
  • 读取消息用conn.ReadMessage(),返回(int, []byte, error),第一个值是消息类型(websocket.TextMessagewebsocket.BinaryMessage
  • 发送消息用conn.WriteMessage(),第二个参数必须是[]byte;若传字符串,需先转[]byte("hello")
  • 连接应显式关闭:conn.Close(),否则可能泄漏goroutine和文件描述符
package main

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

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Upgrade error:", err)
		return
	}
	defer conn.Close()

	for {
		_, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println("Read error:", err)
			break
		}
		if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
			log.Println("Write error:", err)
			break
		}
	}
}

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

客户端:用websocket.Dial连接并处理断线重连

浏览器端用new WebSocket("ws://localhost:8080/ws")即可,但Go客户端需主动拨号。常见陷阱是忽略TLS配置(wss://需传&tls.Config{InsecureSkipVerify: true}仅限测试)、未设置读写超时导致goroutine卡死。

立即学习go语言免费学习笔记(深入)”;

  • websocket.DefaultDialer默认无超时,务必设置TLSClientConfigProxy(如需代理)
  • 读写操作可能阻塞,建议用conn.SetReadDeadline()conn.SetWriteDeadline()控制超时
  • 断线后不能复用旧*websocket.Conn,必须重新Dial;重连逻辑需自己实现(例如指数退避)
  • 发送JSON数据时,先json.MarshalWriteMessage;接收时先ReadMessagejson.Unmarshal

消息粘包与并发安全:每个连接应独占一个goroutine

websocket.Conn本身不是并发安全的——多个goroutine同时调用WriteMessage会panic(concurrent write to websocket connection)。但ReadMessage可以并发调用,只要写操作被串行化。

  • 典型模式:一个goroutine循环ReadMessage,另一个goroutine负责WriteMessage,通过chan []byte通信
  • 不要在HTTP handler里直接处理业务逻辑,应把conn交给worker goroutine,并用defer conn.Close()确保清理
  • 大消息(>1MB)可能触发websocket: close sent,需调大Upgrader.ReadBufferSizeWriteBufferSize

真正难的是状态同步和连接生命周期管理,比如用户登录态如何绑定到Conn、如何广播消息给房间内所有人——这些不在WebSocket协议层,得自己设计。

https://www.php.cn/faq/1972060.html

发表回复

Your email address will not be published. Required fields are marked *