【问题标题】:Websocket send to specific client instead broadcastWebsocket 发送到特定客户端而不是广播
【发布时间】:2017-09-08 18:00:51
【问题描述】:

我正在尝试修改 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))
                    }
        }
}

客户

我已向 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
        }
}

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

消息本身以 JSON 格式来自客户端,指定“to”指示要发送的对象和要发送的消息。

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

【问题讨论】:

    标签: go gorilla


    【解决方案1】:

    定义表示消息的类型:

    type Message struct {
        id int
        data []byte
    }
    

    向 Hub 添加一个字段:

    Send chan Message
    

    并与集线器的其他频道一起初始化频道。

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

    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和消息数据并发送给hub:

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

    【讨论】:

    • 谢谢。我们需要默认条款吗?我在集线器中未注册的处理程序做同样的事情。请赐教。
    • 如果您不添加默认子句,则集线器可以阻止死客户端。原始示例中客户端的发送通道的容量大于一(我忘记了确切的值)。如果通道已满,则客户端的发送循环可能会卡在对对等方的写入中。最好是放弃客户端然后停止集线器。
    • 我也在使用 gorilla,和上面的实现非常相似。我希望阻止向创建消息的客户端广播。你将如何做到这一点?
    • 当我登录“客户端”时,我得到:&{0xc421084d50 0xc4210be280 0xc421066240 0} - 你如何让这个人类可读?
    • @zero_cool Client.Id 是唯一人类可读的字段,因此请仅记录该字段。
    猜你喜欢
    • 2012-12-07
    • 2012-01-25
    • 1970-01-01
    • 2019-05-05
    • 2016-02-24
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多