From 0377134a8260310771423cb88604e1c8a67d6105 Mon Sep 17 00:00:00 2001 From: xizhenhua Date: Wed, 13 Dec 2017 15:20:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client.go | 103 ++++++++++++++++++++++++++++------------ home.html | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++---- hub.go | 64 +++++++++++++++++-------- 3 files changed, 247 insertions(+), 57 deletions(-) diff --git a/client.go b/client.go index 1b8d395..b42be4f 100644 --- a/client.go +++ b/client.go @@ -12,16 +12,15 @@ import ( ) const ( - // Time allowed to write a message to the peer. - writeWait = 3 * time.Second + // 写消息允许的等待时间 + writeWait = 10 * time.Second - // Time allowed to read the next pong message from the peer. - pongWait = 3 * time.Second + // 心跳允许的等待时间 + pongWait = 60 * time.Second - // Send pings to peer with this period. Must be less than pongWait. pingPeriod = (pongWait * 9) / 10 - // Maximum message size allowed from peer. + // 发送消息最大的字节数 maxMessageSize = 512 ) @@ -35,7 +34,7 @@ var upgrader = websocket.Upgrader{ WriteBufferSize: 1024, } -// Client is a middleman between the websocket connection and the hub. +// 客户端 type Client struct { hub *Hub @@ -46,7 +45,24 @@ type Client struct { send chan []byte // uuid - uUID string + uuid string + + // nickname + nickName string +} + +// UserInfo 用户信息 +type UserInfo struct { + UUID string + NickName string + Client *Client +} + +// 待发送消息 +type Broad struct { + Content []byte + Rtype int64 + Client *Client } // Msg 消息体 @@ -54,15 +70,21 @@ type Msg struct { Code int Rtype int From string + To string Content string - Uids []string + User map[string]string + NowUID string +} + +// 读取消息体 +type ReadMsg struct { + Content string + FromNick string + MsgFrom string + MsgTo string } -// readPump pumps messages from the websocket connection to the hub. -// -// The application runs readPump in a per-connection goroutine. The application -// ensures that there is at most one reader on a connection by executing all -// reads from this goroutine. +// 读取消息 func (c *Client) readPump() { defer func() { c.hub.unregister <- c @@ -82,21 +104,34 @@ func (c *Client) readPump() { message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) //写入消息 var msg Msg + var readMsg ReadMsg msg.Code = 200 msg.Rtype = 1 + msg.From = c.uuid msg.Content = string(message) + json.Unmarshal([]byte(msg.Content), &readMsg) + msg.To = readMsg.MsgTo msgJSON, err := json.Marshal(msg) + var broad Broad + broad.Content = msgJSON + if readMsg.MsgTo == "ALL" { + broad.Rtype = 1 + } else { + broad.Rtype = 2 + if _, ok := c.hub.userINFO[msg.To]; ok { + broad.Client = c.hub.userINFO[msg.To].Client + } else { + // + continue + } + } if err == nil { - c.hub.broadcast <- msgJSON + c.hub.broadcast <- broad } } } -// writePump pumps messages from the hub to the websocket connection. -// -// A goroutine running writePump is started for each connection. The -// application ensures that there is at most one writer to a connection by -// executing all writes from this goroutine. +// 写消息 func (c *Client) writePump() { ticker := time.NewTicker(pingPeriod) defer func() { @@ -139,7 +174,7 @@ func (c *Client) writePump() { } } -// serveWs handles websocket requests from the peer. +// websocket服务架设 func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { @@ -149,25 +184,35 @@ func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) { client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)} client.hub.register <- client + //获取昵称 + nickName := r.FormValue("nick") + client.nickName = nickName + //分配UUID uid := uuid.NewV4().String() - client.uUID = uid - hub.uuids[client.uUID] = uid + client.uuid = uid + + //构建用户实体 + userInfo := &UserInfo{UUID: uid, NickName: nickName, Client: client} + hub.userINFO[uid] = userInfo //实验阶段每次有人进入则把所有用户UUID发送到客户端 var msg Msg - for num := range hub.uuids { - msg.Uids = append(msg.Uids, num) + var users = make(map[string]string) + for _, vlue := range hub.userINFO { + users[vlue.UUID] = vlue.NickName } + msg.User = users msg.Code = 200 msg.Rtype = 2 + msg.NowUID = uid msgJSON, err := json.Marshal(msg) + var broad Broad + broad.Content = msgJSON + broad.Rtype = 1 if err == nil { - client.hub.broadcast <- msgJSON + client.hub.broadcast <- broad } - - // Allow collection of memory referenced by the caller by doing all work in - // new goroutines. go client.writePump() go client.readPump() } diff --git a/home.html b/home.html index 28127c4..0bfeea5 100644 --- a/home.html +++ b/home.html @@ -2,11 +2,29 @@ Chat Example + +
+
+

用户列表

+ + +
- + + 发送对象: +
\ No newline at end of file diff --git a/hub.go b/hub.go index eb547e2..71b9a34 100644 --- a/hub.go +++ b/hub.go @@ -1,31 +1,31 @@ package main -// hub maintains the set of active clients and broadcasts messages to the -// clients. +import "encoding/json" + +// Hub 核心结构体 type Hub struct { - // Registered clients. + // 注册客户端 clients map[*Client]bool - // Inbound messages from the clients. - broadcast chan []byte + // 消息通道 + broadcast chan Broad - // Register requests from the clients. register chan *Client - // Unregister requests from clients. + // 卸载客户端 unregister chan *Client // Uid from clients. - uuids map[string]string + userINFO map[string]*UserInfo } func newHub() *Hub { return &Hub{ - broadcast: make(chan []byte), + broadcast: make(chan Broad), register: make(chan *Client), unregister: make(chan *Client), clients: make(map[*Client]bool), - uuids: make(map[string]string), + userINFO: make(map[string]*UserInfo), } } @@ -34,21 +34,47 @@ func (h *Hub) run() { select { case client := <-h.register: h.clients[client] = true - //当有人连接,把新链接的UUID发送给前台 暂时把它当消息写到通道就行,然后让前台去解析 - case client := <-h.unregister: if _, ok := h.clients[client]; ok { delete(h.clients, client) - delete(h.uuids, client.uUID) + delete(h.userINFO, client.uuid) close(client.send) } - //当有人退出,把退出的相关UUID发送给前台 暂时把它当消息写到通道就行,然后让前台去解析 - - case message := <-h.broadcast: - //log.Println("当前连接:", string([]byte(message))) - for client := range h.clients { + //更新客户端列表 + var msg Msg + var users = make(map[string]string) + for _, vlue := range h.userINFO { + users[vlue.UUID] = vlue.NickName + } + msg.User = users + msg.Code = 200 + msg.Rtype = 2 + msgJSON, err := json.Marshal(msg) + if err == nil { + for client := range h.clients { + select { + case client.send <- msgJSON: + default: + close(client.send) + delete(h.clients, client) + } + } + } + case broad := <-h.broadcast: + if broad.Rtype == 1 { + for client := range h.clients { + select { + case client.send <- broad.Content: + default: + close(client.send) + delete(h.clients, client) + } + } + } + if broad.Rtype == 2 { + client := broad.Client select { - case client.send <- message: + case client.send <- broad.Content: default: close(client.send) delete(h.clients, client)