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

I'm trying to modify the gorilla chat example to to send a message to a specific client instead of broadcast. First I'm storing the specific client in the hub against it's 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

I've added a field Id int to Client to know which client has sent a message

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
        }
}

What are the next steps to take to be able to send the message to a specific client instead of broadcasting.

the message itself is coming as JSON from the client specifying 'to' indicating who to send and what message to send.

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

1个回答

Define a type representing a message:

type Message struct {
    id int
    data []byte
}

Add a field to Hub:

Send chan Message

and initialize the channel along with the hub's other channels.

Add the following case to the hub's 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)
        }
    }

In the client's receive loop, parse the JSON to get the id and message data and send it to the hub:

    c.Hub.Send <- Message{id: id, data: data}
douhutongvm382381
douhutongvm382381 看来我所有的浏览器选项卡都具有相同的ID-聊天按预期进行。 您如何获得每个客户一个唯一的ID?
大约 2 年之前 回复
doubi12138
doubi12138 通过“接收循环”(在上面的答案中),您是说readPump函数吗?
大约 2 年之前 回复
douguachi0056
douguachi0056 当我登录“客户端”时,我得到:&{0xc421084d50 0xc4210be280 0xc421066240 0}-您如何使人类可读?
大约 2 年之前 回复
dongzhong7299
dongzhong7299 如何初始化到发送客户端? 好吧-以防万一...
大约 2 年之前 回复
douxian9943
douxian9943 我也在使用大猩猩,与上面的实现非常相似。 我希望防止广播到创建该消息的客户端。 您将如何实现?
大约 2 年之前 回复
drrc61668568
drrc61668568 如果不添加默认子句,则集线器可以阻止死的客户端。 在原始示例中,客户端的发送通道的容量大于1(我忘记了确切的值)。 如果通道已满,则客户端的发送循环可能会阻塞对同级设备的写入。 最好先放下客户端,然后再停放集线器。
3 年多之前 回复
dousui8263
dousui8263 谢谢。 我们需要默认子句吗? 我已经在中心未注册的处理程序执行相同的操作。 请指教。
3 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问