第三章节: WebSocketServer连接管理

前言

上一章节中我们在Server端通过HttpHeader中携带的Token识别了每个客户端连接,本章节我们将用户和WebSocket连接一一绑定并统一管理。

连接管理器设计

因此我们设计一个ConnManager,它需要具备以下功能:

  • 需要维护一个Map,Key为UserID, Value为WebSocketConnection,表示用户与连接的对应关系
  • 需要有方法AddConn(UserID, WebSocketConnection)来添加新的用户和连接
  • 需要通过UserID来获取WebSocketConnection
  • 需要有移除WebSocketConnection的方法
  • 需要考虑并发下的线程安全

在go-im/src目录下新建文件夹conn, 在conn下新建conn.go

go 复制代码
package conn

import (
    "fmt"
    "sync"

    "aoki.com/go-im/src/model"
    "github.com/gorilla/websocket"
)

type ConnManager struct {
    // 考虑线程安全
    connections sync.Map
}

var m *ConnManager = &ConnManager{
    connections: sync.Map{},
}

// 保证单例
func GetConnManager() *ConnManager {
    return m
}

// 根据UserID获取连接
func (m *ConnManager) FindConn(userID int64) *websocket.Conn {
     conn, has := m.connections.Load(userID)
     if has {
        return conn.(*websocket.Conn)
     }
     return nil
}

// 添加新的连接
func (m *ConnManager) AddConn(userID int64, conn *websocket.Conn) {
    m.connections.Store(userID, conn)
}

// 移除连接
func (m *ConnManager) DelConn(userID int64) {
    m.connections.Delete(userID)
}

处理连接逻辑

在有新连接时需要通过ConnManager来添加新绑定,当有连接断开时需要通过ConnManager来释放绑定

修改server.go

go 复制代码
package main

import (
    "log"
    "net/http"

    "aoki.com/go-im/src/conn"
    "aoki.com/go-im/src/model"
    "github.com/gin-gonic/gin"
    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    // Allow Cross Origin
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

var ConnManager *conn.ConnManager = conn.GetConnManager()

func ws(c *gin.Context) {
    conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
    if err != nil {
        panic(err)
    }
    defer conn.Close()
    user := model.ResolveUser(c.Request)
    if user == nil {
        log.Println("ResolveUser failed...")
        return
    }
    // 添加新的连接绑定
    ConnManager.AddConn(user.ID, conn)
    log.Printf("%s connected... \n", user.Name)
    // 方法退出时移除连接绑定
    defer OnDisconnect(*user)
    for {
        mt, message, err := conn.ReadMessage()
        if err != nil {
            log.Printf("Read Message Failed... \n", err)
            break
        }
        // 读到什么往WS客户端发什么
        log.Printf("Received Message %s... \n", message)
        err = conn.WriteMessage(mt, message)
        if err != nil {
            log.Printf("Write Message Failed... \n", err)
            break
        }
    }

}

func OnDisconnect(user model.User) {
    log.Printf("%v disconnect...\n", user.Name)
    ConnManager.DelConn(user.ID)
}

func main() {
    server := gin.Default()
    server.GET("/ws", ws)
    server.Run("localhost:8848")
}

调试

分别在两个Terminal启动server和client,然后关闭client进程,可以在Server端的Terminal中看到以下日志输出,说明调试结果符合期望

小结

本章节中我们成功将每个WebSocket连接和用户进行绑定,并通过ConnManager统一管理,这样已经为客户端之间的相互通信做好了铺垫,下一章节我们将实现用户A和用户B之间进行一对一聊天

相关推荐
拾伍廿肆2 天前
python - websocket
python·websocket·django
Sun_Sherry2 天前
FastAPI: websocket的用法及举例
websocket·网络协议·fastapi
貂蝉空大2 天前
uni-app 封装websocket 心跳检测,开箱即用
websocket·网络协议·uni-app
白鹭float.3 天前
【Unity AI】基于 WebSocket 和 讯飞星火大模型
人工智能·websocket·unity
滔滔不绝tao3 天前
五子棋双人对战项目(4)——匹配模块(解读代码)
spring boot·websocket
极客小张4 天前
智能教室云平台管理系统:基于Spring Boot、WebSocket与传感器的设计方案
c语言·spring boot·后端·stm32·物联网·websocket·毕业设计
IT小白34 天前
使用 Node.js 创建一个 WebSocket 服务器
websocket·node.js
Jiaberrr5 天前
解锁微信小程序新技能:ECharts动态折线图搭配WebSocket,数据刷新快人一步!
前端·javascript·websocket·微信小程序·echarts
沥川同学6 天前
计算机网络自顶向下(2)----socket编程
linux·网络·websocket·tcp/ip·计算机网络·udp
浩水浮生7 天前
redis 的发布订阅解决分布式下的websocket session 共享问题
redis·分布式·websocket