Gin利用WebSocket实现在线聊天室
引言
使用WebSocket实现实时的在线聊天室有以下3个技术难点:
1.实时记录每个用户都在线状态,并实时更新在线用户数量
2.实时接收客户端的消息并广播到所有客户端
3.唯一记录和标识每一个客户端
数据结构的定义
客户端结构体定义
type Client struct {
ID string
IpAddress string
IpSource string
UserId interface{
}
Socket *websocket.Conn
Send chan []byte
Start time.Time
ExpireTime time.Duration // 一段时间没有接收到心跳则过期
}
其中Start是记录客户端最后一次给服务端发送消息的时间,ExpirTime则表示是在ExpirTime时间内如果服务端没有接收客户端发送过来的消息就代表对应客户端已经下线。Socket则是用来记录客户端和服务端直接到WebSocket连接。
管理使用在线客户端结构体定义
type ClientManager struct {
Clients map[string]*Client // 记录在线用户
Broadcast chan []byte //触发消息广播
Register chan *Client // 触发新用户登陆
UnRegister chan *Client // 触发用户退出
}
由于在本案例中每个客户端都有自己独立的goroutine,所以利用channel保证多个goroutine之间的正常通信,进而保证每个客户端之间正常的消息通讯
消息体的定义
type WsMessage struct {
Type int `json:"type"`
Data interface{
} `json:"data"`
}
Client对应方法的定义
Read方法的定义
// Read 读取客户端发送过来的消息
func (c *Client) Read() {
// 出现故障后把当前客户端注销
defer func() {
_ = c.Socket.Close()
Manager.UnRegister <- c
}()
for {
_, data, err := c.Socket.ReadMessage()
if err != nil {
logger.Error(err.Error())
break
}
var msg WsMessage
err = json.Unmarshal(data, &msg)
if err != nil {
logger.Error(err.Error())
break
}
switch msg.Type {
case 6:
// 如果是心跳监测消息(利用心跳监测来判断对应客户端是否在线)
resp, _ := json.Marshal(&WsMessage