網(wǎng)站首頁 編程語言 正文
一、依賴包的安裝
-
1、在
go
語言中常見的websocket
包有以下兩個-
github
地址,優(yōu)先選擇別人封裝好的 - 官方包
-
-
2、選擇
set
集合包,鏈接地址 -
3、在
gin
框架中使用,鏈接地址
二、在gin
中使用websocket
-
1、接入鑒權(quán)
websocket
也可以和普通api
接口一樣的做一個接口鑒權(quán)(token
機制),如果驗證通過可以繼續(xù)往下走,沒有驗證不能往下走func Chat(ctx *gin.Context) { var upGrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { // 根據(jù)鑒權(quán)的方式來處理,如果不想鑒權(quán)的就直接返回true,如果需要鑒權(quán)就要根據(jù)判斷來返回true,或者false return true }, } }
-
2、實現(xiàn)鑒權(quán)處理
func Chat(ctx *gin.Context) { // 根據(jù)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 { // 根據(jù)判斷token的方法來鑒權(quán),如果沒token就返回false return isValied }, } } // 內(nèi)部使用判斷token合法 func checkToken(userId int64, token string) bool { ... return true }
-
3、將普通的
get
請求升級為websocket
請求... //升級get請求為webSocket協(xié)議 conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil) if err != nil { fmt.Println("websocket連接錯誤") return }
-
4、
conn
連接句柄的維護// Node 當前用戶節(jié)點 userId和Node的映射關(guān)系 type Node struct { Conn *websocket.Conn DataQueue chan []byte // 群組的消息分發(fā) GroupSet set.Interface } // 映射關(guān)系表 var clientMap map[int64]*Node = make(map[int64]*Node, 0) // 讀寫鎖 var rwLocker sync.RWMutex
-
5、每次創(chuàng)建連接后將映射關(guān)系進行綁定
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 { // 根據(jù)判斷token的方法來鑒權(quán),如果沒token就返回false return isValied }, } //升級get請求為webSocket協(xié)議 conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil) if err != nil { fmt.Println("websocket連接錯誤") return } // 綁定到當前節(jié)點 node := &Node{ Conn: conn, DataQueue: make(chan []byte, 50), GroupSet: set.New(set.ThreadSafe), } // 映射關(guān)系的綁定 rwLocker.Lock() clientMap[userIdInt] = node rwLocker.Unlock() }
-
6、創(chuàng)建一個發(fā)送消息到管道中
// 將數(shù)據(jù)推送到管道中 func sendMsg(userId int64, message []byte) { rwLocker.RLock() node, isOk := clientMap[userId] rwLocker.RUnlock() if isOk { node.DataQueue <- message } }
-
7、創(chuàng)建一個方法從管道中獲取數(shù)據(jù)發(fā)送給前端
// 從管道中獲取數(shù)據(jù)發(fā)送出去 func senProc(node *Node) { for { select { case data := <-node.DataQueue: err := node.Conn.WriteMessage(websocket.TextMessage, data) if err != nil { fmt.Println("發(fā)送消息失敗") return } } } }
-
8、在
Chat
方法中使用func Chat(ctx *gin.Context) { ... // 連接成功就給當前用戶發(fā)送一個hello word sendMsg(userIdInt, []byte("hello word")) // 發(fā)送數(shù)據(jù)給客戶端 go senProc(node) }
-
9、接收客戶端消息轉(zhuǎn)發(fā)給另外一個用戶
// 接收客戶端數(shù)據(jù) func recvProc(node *Node) { for { _, data, err := node.Conn.ReadMessage() if err != nil { fmt.Println("接收數(shù)據(jù)失敗", err) return } // 將數(shù)據(jù)處理轉(zhuǎn)發(fā)給對應(yīng)的人 dispatch(data) } } // 分發(fā)數(shù)據(jù) func dispatch(data []byte) { type Message struct { UserId int64 `json:"userId"` Msg string `json:"msg"` } fmt.Println("接收到的數(shù)據(jù)", string(data)) // 解析出數(shù)據(jù) message := Message{} err := json.Unmarshal(data, &message) if err != nil { fmt.Println("解析數(shù)據(jù)失敗:", err.Error()) return } fmt.Println("解析的數(shù)據(jù)為:", message) // 發(fā)送數(shù)據(jù) sendMsg(message.UserId, data) }
-
10、使用接收客戶端數(shù)據(jù)的方法
func Chat(ctx *gin.Context) { ... // 連接成功就給當前用戶發(fā)送一個hello word sendMsg(userIdInt, []byte("hello word")) // 發(fā)送數(shù)據(jù)給客戶端 go senProc(node) // 接收客戶端的數(shù)據(jù) go recvProc(node) }
-
11、定義一個對外的方法(比如在別的接口中要發(fā)送數(shù)據(jù)到
websocket
中)func SendMessage(userId int64, message interface{}) { str, _ := json.Marshal(message) sendMsg(userId, str) }
三、消息群聊的使用
常見的場景有群聊,一個后臺用戶要給自己的顧客推送促銷消息,這里就舉例用后臺給顧客推送促銷消息
-
1、根據(jù)當前連接的用戶
id
來加入對應(yīng)的群聊// 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) { ... // 根據(jù)當前用戶的id來加入群組 AddGroupByAccountId(userIdInt) ... }
-
3、推送消息,循環(huán)連接的
Map
判斷如果當前用戶在這個群聊里面就發(fā)送數(shù)據(jù)到管道中// 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、處理群聊過程中臨時加入群聊的,直接在加入的時候調(diào)用加入群組的方法就可以
原文鏈接:https://blog.csdn.net/kuangshp128/article/details/126260011
相關(guān)推薦
- 2022-05-05 Flutter如何保證數(shù)據(jù)操作原子性詳解_Android
- 2022-05-25 Go語言的type?func()用法詳解_Golang
- 2022-06-14 Go操作redis與redigo的示例解析_Golang
- 2022-12-23 C++中類的成員函數(shù)及內(nèi)聯(lián)函數(shù)使用及說明_C 語言
- 2023-01-02 Flutter?包管理器和資源管理使用學(xué)習(xí)_Android
- 2022-07-27 Docker-Compose搭建Spark集群的實現(xiàn)方法_docker
- 2022-03-03 【css】page-break-after 頁面打印分頁屬性
- 2022-04-23 elementui el-pagination 分頁組件封裝
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支