package ws_handler import ( "common/log" "common/net/socket" "context" "go.uber.org/zap" "runtime/debug" "sync" "time" ) type Client struct { sync.WaitGroup conn socket.ISocketConn // Socket mailChan chan Event // 邮箱队列 logger *zap.SugaredLogger ctx context.Context cancel context.CancelFunc heartBeat time.Time UID int32 } func NewClient(uid int32, conn socket.ISocketConn) *Client { client := &Client{} client.UID = uid client.conn = conn client.logger = log.GetLogger().Named("uid").With("uid", client.UID) client.logger.Errorf("错误日志 %v", 1) client.heartBeat = time.Now() client.mailChan = make(chan Event, 1024) client.ctx, client.cancel = context.WithCancel(context.Background()) go client.Loop() return client } // CloseClient 关闭客户端 func (c *Client) CloseClient() { if c.cancel != nil { c.cancel() c.Wait() } } func (c *Client) onClose() { if c.conn != nil { _ = c.conn.Close() c.conn = nil } if c.mailChan != nil { close(c.mailChan) c.mailChan = nil } UserMgr.Delete(c.UID) c.Done() } func (c *Client) Loop() { defer func() { if err := recover(); err != nil { c.logger.Errorf("Client Loop err: %v", err) debug.PrintStack() } }() defer c.onClose() c.Add(1) //心跳检测 hearBeatTicker := time.NewTicker(3000 * time.Millisecond) for { select { case <-c.ctx.Done(): return case _, _ = <-c.mailChan: case <-hearBeatTicker.C: // 心跳超时直接关掉连接 if c.checkHeartBeatTimeout() { return } } } } func (c *Client) checkHeartBeatTimeout() bool { sub := time.Now().Sub(c.heartBeat) return sub > 60*time.Second }