Websocket 发送到特定客户端而不是广播

Websocket send to specific client instead broadcast

我正在尝试将大猩猩聊天示例修改为向特定客户端发送消息而不是广播。首先,我根据其 ID 将特定客户端存储在集线器中。

Hub.go

type Hub struct {
        Clients    map[int]*Client // Changed this piece to store id (int)
        Broadcast  chan []byte   
        Register   chan *Client   
        Unregister chan *Client   
}

func (h *Hub) Run() {
        for {
                    select {
                    case client := <-h.Register:
                                fmt.Println("hub client register")
                                h.Clients[client.Id] = client
                    case client := <-h.Unregister:
                                fmt.Println("hub client Unregister")
                                fmt.Println(h.Clients[client.Id])
                                if h.Clients[client.Id] != nil {
                                            delete(h.Clients, client.Id)
                                            close(client.Send)
                                }
                    case message := <-h.Broadcast:
                                fmt.Println("to send to a specific client", string(message))
                    }
        }
}

客户端

我给客户端添加了一个字段 Id int 来知道哪个客户端发送了消息

type Client struct {
        Hub  *Hub
        Conn *websocket.Conn
        Send chan []byte    
        Id   int // Id of the client,
}

func (c *Client) readPump() {
        defer func() {
                    c.Hub.Unregister <- c
                    c.Conn.Close()
        }()
        c.Conn.SetReadLimit(maxMessageSize)
        c.Conn.SetReadDeadline(time.Now().Add(pongWait))
        c.Conn.SetPongHandler(func(string) error { c.Conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
        for {
                    _, message, err := c.Conn.ReadMessage()
                    if err != nil {
                                if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
                                            log.Printf("error: %v", err)
                                }
                                break
                    }
                    message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))

                    fmt.Println("client read message", string(message), "from", c.Id)
        // {"to":512,"message":"Hi there."}
                    c.Hub.Broadcast <- message
        }
}

接下来要采取哪些步骤才能将消息发送到特定客户端而不是广播。

消息本身作为 JSON 来自客户端,指定 'to' 指示发送给谁以及发送什么消息。

{"to":512,"message":"Hi there."}

定义表示消息的类型:

type Message struct {
    id int
    data []byte
}

向 Hub 添加字段:

Send chan Message

并初始化该通道以及集线器的其他通道。

将以下案例添加到中心的 select:

case m := <-h.Send:
    c, ok := clients[m.id]
    if ok {
        select {
        case c.send <- m.data:
        default:
           delete(h.Clients, c.Id)
           close(c.Send)
        }
    }

在客户端的接收循环中,解析JSON以获取id和消息数据并将其发送到集线器:

    c.Hub.Send <- Message{id: id, data: data}