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

Dev*_*per 5 go gorilla

我正在尝试修改大猩猩聊天示例,以将消息发送到特定客户端而不是广播。首先,我根据特定客户端的 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))
                    }
        }
}
Run Code Online (Sandbox Code Playgroud)

客户

我在 Client 中添加了一个 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
        }
}
Run Code Online (Sandbox Code Playgroud)

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

消息本身以 JSON 形式来自客户端,指定“to”指示要发送给谁以及要发送什么消息。

{"to":512,"message":"Hi there."}
Run Code Online (Sandbox Code Playgroud)

Cer*_*món 3

定义一个表示消息的类型:

type Message struct {
    id int
    data []byte
}
Run Code Online (Sandbox Code Playgroud)

向 Hub 添加字段:

Send chan Message
Run Code Online (Sandbox Code Playgroud)

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

将以下案例添加到集线器的选择中:

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)
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

    c.Hub.Send <- Message{id: id, data: data}
Run Code Online (Sandbox Code Playgroud)