golang,go,博客,开源,编程

go构建websocket服务

Published on with 0 views and 0 comments

在 Go 语言中实现 WebSocket 可以使用 gorilla/websocket 库,这是一个流行且成熟的 WebSocket 实现库,广泛应用于 Go Web 开发中。下面是一个简单的 Go WebSocket 实现示例,包含了 WebSocket 服务端和客户端的基本实现。

1. 安装 Gorilla WebSocket 库

首先,需要安装 gorilla/websocket 包:

go get github.com/gorilla/websocket

2. WebSocket 服务器端实现

WebSocket 服务器端会监听来自客户端的 WebSocket 连接请求,并能向客户端发送消息。

package main

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

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true // 忽略跨域检查
	},
}

func handleConnection(w http.ResponseWriter, r *http.Request) {
	// 升级 HTTP 请求为 WebSocket 协议
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()

	// 打印客户端连接信息
	log.Printf("Client connected: %s", conn.RemoteAddr())

	for {
		// 读取客户端发送的消息
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		// 打印收到的消息
		fmt.Printf("Received message: %s\n", p)

		// 向客户端发送消息
		err = conn.WriteMessage(messageType, p)
		if err != nil {
			log.Println(err)
			return
		}
	}
}

func main() {
	http.HandleFunc("/ws", handleConnection)

	// 启动 WebSocket 服务,监听在 8080 端口
	log.Println("WebSocket server starting on ws://localhost:8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

代码说明:

  1. websocket.Upgrader: 用于升级 HTTP 请求为 WebSocket 协议。CheckOrigin 函数用于跳过跨域检查,实际应用中可以根据需要做安全控制。
  2. handleConnection: 处理每个 WebSocket 连接,持续接收客户端消息并将其返回给客户端。
  3. conn.ReadMessage: 读取客户端发送的消息。
  4. conn.WriteMessage: 向客户端发送消息。

启动 WebSocket 服务:

执行上述 Go 文件,启动 WebSocket 服务器:

go run main.go

服务会监听 ws://localhost:8080/ws,接收 WebSocket 连接。


3. WebSocket 客户端实现

WebSocket 客户端可以使用 Go 的 gorilla/websocket 库通过 Dial 函数与服务器建立 WebSocket 连接。

package main

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

func main() {
	// 连接到 WebSocket 服务器
	url := "ws://localhost:8080/ws"
	conn, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		log.Fatal("dial:", err)
		os.Exit(1)
	}
	defer conn.Close()

	// 发送一条消息到服务器
	message := "Hello, WebSocket server!"
	err = conn.WriteMessage(websocket.TextMessage, []byte(message))
	if err != nil {
		log.Println("Error sending message:", err)
		return
	}
	fmt.Println("Sent:", message)

	// 读取服务器的响应
	_, message, err := conn.ReadMessage()
	if err != nil {
		log.Println("Error reading message:", err)
		return
	}

	fmt.Printf("Received: %s\n", message)
}

代码说明:

  1. websocket.DefaultDialer.Dial: 用于与 WebSocket 服务器建立连接。
  2. conn.WriteMessage: 向 WebSocket 服务器发送消息。
  3. conn.ReadMessage: 接收 WebSocket 服务器发送的消息。

运行客户端:

执行 WebSocket 客户端程序,客户端会连接到 WebSocket 服务器并发送消息。服务器会返回相同的消息。

go run client.go

4. 完整流程

  • 客户端连接到 WebSocket 服务器。
  • 客户端发送消息(如“Hello, WebSocket server!”)到服务器。
  • 服务器接收消息后,打印并将其原封不动地返回给客户端。
  • 客户端接收到服务器返回的消息并打印。

5. WebSocket 服务器功能扩展

你可以进一步扩展 WebSocket 服务器,支持如下功能:

  • 广播消息:服务器向所有连接的客户端发送消息。
  • 身份验证:在 WebSocket 连接时进行身份验证(如 JWT)。
  • 消息存储:将收到的消息保存到数据库。
  • 心跳检测:定期检测客户端是否在线,避免断开的连接长期保持。

例如,广播功能的扩展示例:

package main

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

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

var clients = make(map[*websocket.Conn]bool) // 用来存储所有连接的客户端
var broadcast = make(chan string)             // 用来广播消息
var mu sync.Mutex                             // 防止并发读写

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

	// 添加连接到客户端列表
	mu.Lock()
	clients[conn] = true
	mu.Unlock()

	for {
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			break
		}
		// 将收到的消息广播给所有连接的客户端
		broadcast <- string(p)

		// 向客户端回传消息
		err = conn.WriteMessage(messageType, p)
		if err != nil {
			log.Println(err)
			break
		}
	}

	// 断开连接时删除客户端
	mu.Lock()
	delete(clients, conn)
	mu.Unlock()
}

func broadcastMessages() {
	for {
		msg := <-broadcast
		// 向所有连接的客户端发送消息
		mu.Lock()
		for client := range clients {
			err := client.WriteMessage(websocket.TextMessage, []byte(msg))
			if err != nil {
				log.Println("Error broadcasting message:", err)
				client.Close()
				delete(clients, client)
			}
		}
		mu.Unlock()
	}
}

func main() {
	http.HandleFunc("/ws", handleConnection)

	go broadcastMessages()

	log.Println("WebSocket server starting on ws://localhost:8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

在这个扩展中,服务器会将每个客户端的消息广播给所有其他客户端。


6. 总结

通过 gorilla/websocket 库,Go 可以轻松实现 WebSocket 服务端和客户端,支持全双工、实时消息交换。你可以基于此基础扩展更多功能,如身份验证、心跳检测和消息广播等。


标题:go构建websocket服务
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/01/06/1736153878843.html
联系:scotttu@163.com