網站首頁 編程語言 正文
一、依賴包的安裝
-
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 *http.Request) 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 *http.Request) 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 *http.Request) 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、處理群聊過程中臨時加入群聊的,直接在加入的時候調用加入群組的方法就可以
原文鏈接:https://blog.csdn.net/kuangshp128/article/details/126260011
- 上一篇:數據結構之有頭鏈表的實現
- 下一篇:Spring框架常考知識點總結
相關推薦
- 2022-04-22 Error:Module “./antd/es/badge/style“ does not exis
- 2023-11-14 樹莓派以及linux ubuntu 上,各種依賴不滿足,修復不了:E: Release file f
- 2022-10-16 Android基于方法池與回調實現登錄攔截的場景_Android
- 2022-09-15 利用Anaconda創建虛擬環境的全過程_python
- 2022-10-29 STDC分割網絡:onnx推理
- 2022-03-07 golang強制類型轉換和類型斷言_Golang
- 2023-12-20 Git同時配置Gitee和GitHub
- 2022-07-22 對稱式加密與非對稱式加密的對比
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支