package main
import (
"fmt"
"net/http"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
var (
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
// 允许所有来源的WebSocket连接,这是一个简单示例
return true
},
}
userConnections = make(map[string]*websocket.Conn)
mu sync.Mutex
broadcast = make(chan Message)
pingInterval = 6 * time.Second // 检测连接是否存活的时间间隔
)
// Message 结构用于存储消息和目标用户
type Message struct {
To []string
Message string
}
func main() {
r := gin.Default()
// 启动一个协程来处理消息广播
go handleBroadcast()
// WebSocket路由
r.GET("/ws", func(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 获取用户标识(假设通过认证或其他方式获得)
userID := c.Query("user_id")
if userID == "" {
fmt.Println("未提供用户标识")
return
}
// 存储用户连接
mu.Lock()
userConnections[userID] = conn
mu.Unlock()
// 处理WebSocket连接
for {
messageType, p, err := conn.ReadMessage()
if err != nil {
// 从客户端断开连接时,将其从用户连接列表中删除
mu.Lock()
delete(userConnections, userID)
mu.Unlock()
fmt.Println(err)
fmt.Printf("用户断开: %s\n", userID)
return
}
var m Message
m.To = []string{"2", "3"}
m.Message = string(p)
broadcast <- m
// 这里可以处理收到的WebSocket消息
fmt.Printf("收到消息: %s\n", p)
fmt.Printf("messageType收到消息: %s\n", messageType)
}
})
// 定期发送ping消息以保持连接存活
go pingClients()
r.Run(":8111") // 启动Gin应用
}
func handleBroadcast() {
for {
message := <-broadcast
// 发送消息给指定用户
for _, userID := range message.To {
mu.Lock()
conn, found := userConnections[userID]
mu.Unlock()
if found {
err := conn.WriteMessage(websocket.TextMessage, []byte(message.Message))
if err != nil {
fmt.Printf("向用户 %s 发送消息失败:%s\n", userID, err)
continue
}
} else {
fmt.Printf("用户 %s 不在线,消息已缓存\n", userID)
// 这里可以将消息缓存到数据库或其他数据结构中,以供用户上线后发送
}
}
}
}
func pingClients() {
for {
time.Sleep(pingInterval)
mu.Lock()
for userID, conn := range userConnections {
fmt.Printf("向用户 %s 发送Ping消息:\n", userID)
err := conn.WriteMessage(websocket.PingMessage, []byte{})
if err != nil {
mu.Lock()
delete(userConnections, userID)
mu.Unlock()
fmt.Printf("向用户 %s 发送Ping消息失败:%s\n", userID, err)
}
}
mu.Unlock()
}
}
gin+websocket实现
最新推荐文章于 2024-09-17 21:10:35 发布