golang轻量级WebSocket会话处理与广播插件库melody的使用

Golang轻量级WebSocket会话处理与广播插件库melody的使用

Melody是一个基于github.com/gorilla/websocket的WebSocket框架,它抽象了处理WebSocket的繁琐部分,让你可以专注于编写实时应用程序。

主要特性

  • 清晰易用的接口,类似于net/http或Gin
  • 简单的方式向所有或选定的连接会话广播消息
  • 消息缓冲区使并发写入安全
  • 自动处理发送ping/pong心跳以超时断开的会话
  • 在会话上存储数据

安装

go get github.com/olahol/melody

示例1: 聊天应用

这是一个简单的聊天服务器示例,它会将所有接收到的消息广播给所有连接的客户端。

package main

import (
	"net/http"

	"github.com/olahol/melody"
)

func main() {
	m := melody.New() // 创建melody实例

	// 处理根路径请求,返回HTML页面
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "index.html")
	})

	// 处理WebSocket连接请求
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		m.HandleRequest(w, r)
	})

	// 处理接收到的消息,广播给所有客户端
	m.HandleMessage(func(s *melody.Session, msg []byte) {
		m.Broadcast(msg)
	})

	// 启动服务器
	http.ListenAndServe(":5000", nil)
}

示例2: Gophers应用

这个示例展示了如何跟踪连接的客户端,并在连接/断开时通知其他客户端。

package main

import (
	"fmt"
	"net/http"
	"sync/atomic"

	"github.com/olahol/melody"
)

var idCounter atomic.Int64 // 原子计数器用于生成唯一ID

func main() {
	m := melody.New()

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "index.html")
	})

	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		m.HandleRequest(w, r)
	})

	// 处理新连接
	m.HandleConnect(func(s *melody.Session) {
		id := idCounter.Add(1) // 生成唯一ID

		s.Set("id", id) // 将ID存储在会话中

		// 向客户端发送其ID
		s.Write([]byte(fmt.Sprintf("iam %d", id)))
	})

	// 处理断开连接
	m.HandleDisconnect(func(s *melody.Session) {
		if id, ok := s.Get("id"); ok {
			// 通知其他客户端该ID已断开
			m.BroadcastOthers([]byte(fmt.Sprintf("dis %d", id)), s)
		}
	})

	// 处理接收到的消息
	m.HandleMessage(func(s *melody.Session, msg []byte) {
		if id, ok := s.Get("id"); ok {
			// 将消息广播给其他客户端,附带发送者ID
			m.BroadcastOthers([]byte(fmt.Sprintf("set %d %s", id, msg)), s)
		}
	})

	http.ListenAndServe(":5000", nil)
}

常见问题

如果尝试连接到WebSocket时遇到403错误,可以更改允许所有来源主机:

m := melody.New()
m.Upgrader.CheckOrigin = func(r *http.Request) bool { return true }

Melody提供了一种简单而强大的方式来处理WebSocket连接,使得构建实时应用程序变得更加容易。通过上述示例,你可以快速开始使用melody来构建自己的WebSocket应用。


更多关于golang轻量级WebSocket会话处理与广播插件库melody的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang轻量级WebSocket会话处理与广播插件库melody的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Melody - Golang轻量级WebSocket会话处理与广播库

Melody是一个轻量级的Go语言WebSocket库,它建立在gorilla/websocket之上,提供了简洁的API来处理WebSocket会话、广播消息等常见功能。

基本特性

  • 轻量级且易于使用
  • 支持消息广播(全部或部分客户端)
  • 内置会话管理
  • 支持消息过滤
  • 支持自定义消息处理器

安装

go get github.com/olahol/melody

基础用法

1. 创建Melody实例

package main

import (
	"github.com/olahol/melody"
	"net/http"
)

func main() {
	m := melody.New()
	
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		m.HandleRequest(w, r)
	})
	
	http.ListenAndServe(":5000", nil)
}

2. 处理连接事件

m.HandleConnect(func(s *melody.Session) {
    fmt.Println("客户端连接:", s.Request.RemoteAddr)
})

m.HandleDisconnect(func(s *melody.Session) {
    fmt.Println("客户端断开:", s.Request.RemoteAddr)
})

m.HandleMessage(func(s *melody.Session, msg []byte) {
    fmt.Printf("收到来自 %s 的消息: %s\n", s.Request.RemoteAddr, string(msg))
})

3. 广播消息

// 广播给所有连接的客户端
m.Broadcast([]byte("大家好!"))

// 广播给部分客户端(使用过滤器)
m.BroadcastFilter([]byte("新消息"), func(s *melody.Session) bool {
    return s.Request.URL.Query().Get("name") == "admin"
})

进阶用法

1. 会话管理

m.HandleConnect(func(s *melody.Session) {
    // 设置会话值
    s.Set("name", s.Request.URL.Query().Get("name"))
    s.Set("joined", time.Now())
})

m.HandleMessage(func(s *melody.Session, msg []byte) {
    // 获取会话值
    name, _ := s.Get("name")
    joined, _ := s.Get("joined")
    
    fmt.Printf("%s (加入时间: %v) 说: %s\n", name, joined, string(msg))
})

2. 自定义消息处理

type Message struct {
    Type    string `json:"type"`
    Content string `json:"content"`
}

m.HandleMessage(func(s *melody.Session, msg []byte) {
    var message Message
    if err := json.Unmarshal(msg, &message); err != nil {
        s.Write([]byte(`{"error": "invalid message format"}`))
        return
    }
    
    switch message.Type {
    case "chat":
        m.Broadcast(msg)
    case "private":
        // 处理私信逻辑
    default:
        s.Write([]byte(`{"error": "unknown message type"}`))
    }
})

3. 错误处理

m.HandleError(func(s *melody.Session, err error) {
    fmt.Println("发生错误:", err)
    if err := s.Close(); err != nil {
        fmt.Println("关闭会话时出错:", err)
    }
})

完整示例

package main

import (
	"encoding/json"
	"fmt"
	"github.com/olahol/melody"
	"net/http"
	"time"
)

type Message struct {
	Event   string `json:"event"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

func main() {
	m := melody.New()

	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		m.HandleRequest(w, r)
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "index.html")
	})

	// 连接事件
	m.HandleConnect(func(s *melody.Session) {
		name := r.URL.Query().Get("name")
		if name == "" {
			name = "匿名用户"
		}

		s.Set("name", name)
		s.Set("joined", time.Now())

		// 通知所有人有新用户加入
		msg, _ := json.Marshal(Message{
			Event: "join",
			Name:  name,
		})
		m.Broadcast(msg)
	})

	// 断开事件
	m.HandleDisconnect(func(s *melody.Session) {
		name, _ := s.Get("name")
		msg, _ := json.Marshal(Message{
			Event: "leave",
			Name:  name.(string),
		})
		m.Broadcast(msg)
	})

	// 消息处理
	m.HandleMessage(func(s *melody.Session, msg []byte) {
		name, _ := s.Get("name")

		var message Message
		if err := json.Unmarshal(msg, &message); err != nil {
			s.Write([]byte(`{"error": "invalid message"}`))
			return
		}

		message.Name = name.(string)
		message.Event = "message"

		msgBytes, _ := json.Marshal(message)
		m.Broadcast(msgBytes)
	})

	fmt.Println("服务器启动在 :5000")
	http.ListenAndServe(":5000", nil)
}

性能优化建议

  1. 对于高并发场景,考虑使用连接池
  2. 避免在消息处理器中进行耗时操作
  3. 对于大量广播,考虑使用异步方式
  4. 合理设置WebSocket缓冲区大小

Melody是一个简单但功能完善的WebSocket库,适合大多数需要实时通信的Web应用场景。它的轻量级特性使得它特别适合微服务和嵌入式应用。

回到顶部