gin框架中使用websocket发送消息及群聊

网友投稿 1154 2022-09-30

gin框架中使用websocket发送消息及群聊

gin框架中使用websocket发送消息及群聊

一、依赖包的安装

1、在​​go​​语言中常见的​​websocket​​包有以下两个

​​github地址​​,优先选择别人封装好的​​官方包​​

2、选择​​set​​集合包,​​链接地址​​3、在​​gin​​框架中使用,​​链接地址​​

二、在​​gin​​​中使用​​websocket​​

1、接入鉴权

​​websocket​​​也可以和普通​​api​​​接口一样的做一个接口鉴权(​​token​​机制),如果验证通过可以继续往下走,没有验证不能往下走

func Chat(ctx *gin.Context) { var upGrader = websocket.Upgrader{ CheckOrigin: func(r *bool { // 根据鉴权的方式来处理,如果不想鉴权的就直接返回true,如果需要鉴权就要根据判断来返回true,或者false return true }, }}

2、实现鉴权处理

func Chat(ctx *gin.Context) { // 根据url地址上获取当前用户id和token userId := ctx.DefaultQuery("userId", "") token := ctx.DefaultQuery("token", "") userIdInt, _ := strconv.ParseInt(userId, 10, 64) isValied := checkToken(userIdInt, token) var upGrader = websocket.Upgrader{ CheckOrigin: func(r *bool { // 根据判断token的方法来鉴权,如果没token就返回false return isValied }, }}// 内部使用判断token合法func checkToken(userId int64, token string) bool { ... return true}

3、将普通的​​get​​请求升级为​​websocket​​请求

...//升级get请求为webSocket协议conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil)if err != nil { fmt.Println("websocket连接错误") return}

4、​​conn​​连接句柄的维护

// Node 当前用户节点 userId和Node的映射关系type Node struct { Conn *websocket.Conn DataQueue chan []byte // 群组的消息分发 GroupSet set.Interface}// 映射关系表var clientMap map[int64]*Node = make(map[int64]*Node, 0)// 读写锁var rwLocker sync.RWMutex

5、每次创建连接后将映射关系进行绑定

func Chat(ctx *gin.Context) { userId := ctx.DefaultQuery("userId", "") token := ctx.DefaultQuery("token", "") userIdInt, _ := strconv.ParseInt(userId, 10, 64) fmt.Println(token, userId, "=======") isValied := checkToken(userIdInt, token) var upGrader = websocket.Upgrader{ CheckOrigin: func(r *bool { // 根据判断token的方法来鉴权,如果没token就返回false return isValied }, } //升级get请求为webSocket协议 conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil) if err != nil { fmt.Println("websocket连接错误") return } // 绑定到当前节点 node := &Node{ Conn: conn, DataQueue: make(chan []byte, 50), GroupSet: set.New(set.ThreadSafe), } // 映射关系的绑定 rwLocker.Lock() clientMap[userIdInt] = node rwLocker.Unlock()}

6、创建一个发送消息到管道中

// 将数据推送到管道中func sendMsg(userId int64, message []byte) { rwLocker.RLock() node, isOk := clientMap[userId] rwLocker.RUnlock() if isOk { node.DataQueue <- message }}

7、创建一个方法从管道中获取数据发送给前端

// 从管道中获取数据发送出去func senProc(node *Node) { for { select { case data := <-node.DataQueue: err := node.Conn.WriteMessage(websocket.TextMessage, data) if err != nil { fmt.Println("发送消息失败") return } } }}

8、在​​Chat​​方法中使用

func Chat(ctx *gin.Context) { ... // 连接成功就给当前用户发送一个hello word sendMsg(userIdInt, []byte("hello word")) // 发送数据给客户端 go senProc(node)}

9、接收客户端消息转发给另外一个用户

// 接收客户端数据func recvProc(node *Node) { for { _, data, err := node.Conn.ReadMessage() if err != nil { fmt.Println("接收数据失败", err) return } // 将数据处理转发给对应的人 dispatch(data) }}// 分发数据func dispatch(data []byte) { type Message struct { UserId int64 `json:"userId"` Msg string `json:"msg"` } fmt.Println("接收到的数据", string(data)) // 解析出数据 message := Message{} err := json.Unmarshal(data, &message) if err != nil { fmt.Println("解析数据失败:", err.Error()) return } fmt.Println("解析的数据为:", message) // 发送数据 sendMsg(message.UserId, data)}

10、使用接收客户端数据的方法

func Chat(ctx *gin.Context) { ... // 连接成功就给当前用户发送一个hello word sendMsg(userIdInt, []byte("hello word")) // 发送数据给客户端 go senProc(node) // 接收客户端的数据 go recvProc(node)}

11、定义一个对外的方法(比如在别的接口中要发送数据到​​websocket​​中)

func SendMessage(userId int64, message interface{}) { str, _ := json.Marshal(message) sendMsg(userId, str)}

三、消息群聊的使用

常见的场景有群聊,一个后台用户要给自己的顾客推送促销消息,这里就举例用后台给顾客推送促销消息

1、根据当前连接的用户​​id​​来加入对应的群聊

// addGroupByAccountId 加入群聊func AddGroupByAccountId(userId, groupId int64) { fmt.Println(userId, "加入群聊") rwLocker.Lock() node, isOk := FrontClientMap[userId] if isOk { node.GroupSet.Add(groupId) fmt.Println("加入群聊成功") } rwLocker.Unlock()}

2、在连接的时候加入群聊

func Chat(ctx *gin.Context) { ... // 根据当前用户的id来加入群组 AddGroupByAccountId(userIdInt) ...}

3、推送消息,循环连接的​​Map​​判断如果当前用户在这个群聊里面就发送数据到管道中

// 2.websocket推送消息到h5群端for _, v := range frontWs.FrontClientMap { data := gin.H{ "messageType": int64(messageDto.MessageType), "title": messageDto.Title, "content": messageDto.Content, } if v.GroupSet.Has(int64(accountId)) { msg, _ := json.Marshal(data) v.DataQueue <- msg }}

4、处理群聊过程中临时加入群聊的,直接在加入的时候调用加入群组的方法就可以

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring依赖注入(DI)两种方式的示例详解
下一篇:小程序框架如何选择(小程序用什么框架好)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~