封装客户端对象和Ping客户端
当后端程序运行的时候,第一个客户端发送一个消息之后,刷新页面,然后再发送一个消息,此时的消息是第二个客户端发送的,但是后端没把第一个客户端给移除,因为此时它已经失效了。所以我们需要时不时的和客户端进行交流判断它是否有效,无效则从
map
里移除
封装建议客户端对象
package core
import (
"github.com/gorilla/websocket"
"time"
)
type WsClient struct {
conn *websocket.Conn
}
func NewWsClient(conn *websocket.Conn) *WsClient {
return &WsClient{conn: conn}
}
func (ws *WsClient) Ping(wait time.Duration) {
for {
time.Sleep(wait)
err := ws.conn.WriteMessage(websocket.TextMessage, []byte("ping"))
if err != nil {
ClientMap.Remove(ws.conn)
return
}
}
}
存储客户端对象添加移除方法
package core
import (
"github.com/gorilla/websocket"
"log"
"sync"
"time"
)
// 存储客户端对象
// ClientMap 外部公共使用
var ClientMap *ClientMapStruct
func init() {
ClientMap = &ClientMapStruct{}
}
type ClientMapStruct struct {
data sync.Map // key 是客户端IP value 是 WsClient 连接对象
}
func (c *ClientMapStruct) Store(conn *websocket.Conn) {
wsClient := NewWsClient(conn)
c.data.Store(conn.RemoteAddr().String(), wsClient)
go wsClient.Ping(time.Second * 1)
}
// SendAll 向所有客户端发送消息
func (c *ClientMapStruct) SendAll(msg string) {
c.data.Range(func(key, value interface{}) bool {
conn := value.(*WsClient).conn
err := conn.WriteMessage(websocket.TextMessage, []byte(msg))
if err != nil {
c.Remove(conn)
log.Println(err)
}
return true
})
}
func (c *ClientMapStruct) Remove(conn *websocket.Conn) {
c.data.Delete(conn.RemoteAddr().String())
}