Go websocket 服务端客户端代码示例

105 min read

以下是使用 Go 编写的 WebSocket 服务端和客户端代码示例。

WebSocket 服务端代码示例:

package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

// 定义 WebSocket 连接升级器
var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 允许跨域访问
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func main() {
	// 注册 WebSocket 处理函数
	http.HandleFunc("/ws", handleWebSocket)
	// 监听 8080 端口
	http.ListenAndServe(":8080", nil)
}

// 处理 WebSocket 连接
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	// 升级 HTTP 连接为 WebSocket 连接
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 在新的协程中处理 WebSocket 消息
	go handleWebSocketMessage(conn)
}

// 处理 WebSocket 消息
func handleWebSocketMessage(conn *websocket.Conn) {
	for {
		// 读取 WebSocket 消息
		_, message, err := conn.ReadMessage()
		if err != nil {
			fmt.Println(err)
			return
		}

		// 打印消息
		fmt.Printf("Message received: %s\n", message)

		// 回复消息
		err = conn.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			fmt.Println(err)
			return
		}
	}
}

WebSocket 客户端代码示例:

package main

import (
	"fmt"
	"log"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/websocket"
)

func main() {
	// 构造 WebSocket 连接地址
	u := url.URL{Scheme: "ws", Host: "localhost:8080", Path: "/ws"}

	// 连接 WebSocket 服务器
	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close()

	// 启动发送消息协程
	go sendMessage(c)

	// 循环读取消息
	for {
		// 读取 WebSocket 消息
		_, message, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			return
		}
		log.Printf("Message received: %s", message)
	}
}

// 发送消息
func sendMessage(c *websocket.Conn) {
	for i := 0; i < 5; i++ {
		message := []byte(fmt.Sprintf("Hello, %d!", i))

		// 发送消息
		err := c.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			log.Println("write:", err)
			return
		}

		// 等待 1 秒
		time.Sleep(time.Second)
	}

	// 发送关闭消息并关闭连接
	err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
	if err != nil {
		log.Println("write close:", err)
		return
	}
}

// 监听系统信号,关闭连接
func listenSignal(c *websocket.Conn) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	<-ch
	log.Println("interrupt signal received, closing connection")
	err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
	if err != nil {
		log.Println("write close:", err)
		return
	}
	select {
	case <-time.After(1 * time.Second):
	}
	return
}