Websocket send to specific client instead broadcast

huangapple go评论147阅读模式
英文:

Websocket send to specific client instead broadcast

问题

你想修改大猩猩聊天示例,使其能够向特定客户端发送消息,而不是广播给所有客户端。首先,你需要在Hub结构体中存储特定客户端的ID。

Hub.go

type Hub struct {
    Clients    map[int]*Client // 将此部分修改为存储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

我在Client结构体中添加了一个Id字段,用于标识发送消息的客户端。

type Client struct {
    Hub  *Hub
    Conn *websocket.Conn
    Send chan []byte    
    Id   int // 客户端的ID
}

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."}
英文:

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 := &lt;-h.Register:
                                fmt.Println(&quot;hub client register&quot;)
                                h.Clients[client.Id] = client
                    case client := &lt;-h.Unregister:
                                fmt.Println(&quot;hub client Unregister&quot;)
                                fmt.Println(h.Clients[client.Id])
                                if h.Clients[client.Id] != nil {
                                            delete(h.Clients, client.Id)
                                            close(client.Send)
                                }
                    case message := &lt;-h.Broadcast:
                                fmt.Println(&quot;to send to a specific client&quot;, 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 &lt;- 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(&quot;error: %v&quot;, err)
                                }
                                break
                    }
                    message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))

                    fmt.Println(&quot;client read message&quot;, string(message), &quot;from&quot;, c.Id)
        // {&quot;to&quot;:512,&quot;message&quot;:&quot;Hi there.&quot;}
                    c.Hub.Broadcast &lt;- 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.

{&quot;to&quot;:512,&quot;message&quot;:&quot;Hi there.&quot;}

答案1

得分: 3

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

type Message struct {
    id int
    data []byte
}

在 Hub 中添加一个字段:

Send chan Message

并在初始化通道时与 Hub 的其他通道一起初始化。

在 Hub 的 select 中添加以下 case:

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}
英文:

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 := &lt;-h.Send:
    c, ok := clients[m.id]
    if ok {
		select {
		case c.send &lt;- 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 &lt;- Message{id: id, data: data}

huangapple
  • 本文由 发表于 2017年4月13日 03:41:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/43378283.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定