gin+websocket实现

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()
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值