85 lines
1.8 KiB
Go
85 lines
1.8 KiB
Go
|
|
package websocket
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"log"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/gorilla/websocket"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type Client struct {
|
|||
|
|
ID string
|
|||
|
|
Conn *websocket.Conn
|
|||
|
|
Send chan []byte
|
|||
|
|
Context context.Context
|
|||
|
|
CancelFunc context.CancelFunc
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (c *Client) Read(hub *Hub) {
|
|||
|
|
defer func() {
|
|||
|
|
hub.Unregister <- c
|
|||
|
|
c.Conn.Close()
|
|||
|
|
log.Printf("Client %s disconnected\n", c.ID)
|
|||
|
|
c.CancelFunc()
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
c.Conn.SetReadLimit(512)
|
|||
|
|
c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
|||
|
|
c.Conn.SetPongHandler(func(string) error {
|
|||
|
|
c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
|||
|
|
return nil
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
for {
|
|||
|
|
select {
|
|||
|
|
case <-c.Context.Done():
|
|||
|
|
return
|
|||
|
|
default:
|
|||
|
|
_, message, err := c.Conn.ReadMessage()
|
|||
|
|
if err != nil {
|
|||
|
|
log.Printf("Read error from client %s: %v", c.ID, err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
log.Printf("Receive [%s]: %s", c.ID, message)
|
|||
|
|
// 这里你可以把消息发给 hub.Broadcast 或业务处理
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (c *Client) Write() {
|
|||
|
|
ticker := time.NewTicker(54 * time.Second) // 小于读超时,保证ping及时发
|
|||
|
|
defer func() {
|
|||
|
|
ticker.Stop()
|
|||
|
|
c.Conn.Close()
|
|||
|
|
c.CancelFunc()
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
for {
|
|||
|
|
select {
|
|||
|
|
case <-c.Context.Done():
|
|||
|
|
return
|
|||
|
|
case msg, ok := <-c.Send:
|
|||
|
|
if !ok {
|
|||
|
|
// 通道关闭,结束写入
|
|||
|
|
c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
|||
|
|
err := c.Conn.WriteMessage(websocket.TextMessage, msg)
|
|||
|
|
if err != nil {
|
|||
|
|
log.Printf("Write error to client %s: %v", c.ID, err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
case <-ticker.C:
|
|||
|
|
// 发送 ping
|
|||
|
|
c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
|||
|
|
if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
|||
|
|
log.Printf("Ping error to client %s: %v", c.ID, err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|