@@ -60,7 +60,9 @@ type Message struct {
6060 - ` "leave" ` :离开房间请求(当前 Demo 中暂时很少手动用到);
6161 - ` "offer" ` / ` "answer" ` :SDP 交换;
6262 - ` "candidate" ` :ICE 候选;
63- - ` "room_members" ` :服务端广播的当前房间成员列表(从服务端发给前端)。
63+ - ` "room_members" ` :服务端广播的当前房间成员列表(从服务端发给前端);
64+ - ` "ping" ` :可选心跳消息(从前端发给服务端,用于保活/学习);
65+ - ` "pong" ` :服务端对 ` "ping" ` 的可选回应(从服务端发给前端)。
6466- ` Room ` :房间名,字符串。
6567- ` From ` :发送方 ID(前端生成的 ` myId ` )。
6668- ` To ` :接收方 ID,仅点对点消息(` offer/answer/candidate ` )需要。
@@ -110,7 +112,7 @@ type Client struct {
110112 - ` rooms["room1"]["userB"] = *Client `
111113- 处理下列操作:
112114 - WebSocket 连接升级与关闭;
113- - 收到 ` join/leave/offer/answer/candidate ` 消息并处理;
115+ - 收到 ` join/leave/ping/ offer/answer/candidate ` 消息并处理;
114116 - 对 ` offer/answer/candidate ` 按 ` Room + To ` 进行转发;
115117 - 在房间成员变化时,广播 ` room_members ` 消息。
116118
@@ -175,6 +177,11 @@ func (h *Hub) HandleWS(w http.ResponseWriter, r *http.Request) {
175177 h.addClient (client)
176178 case " leave" :
177179 h.removeClient (client)
180+ case " ping" :
181+ select {
182+ case client.send <- Message{Type: " pong" }:
183+ default :
184+ }
178185 case " offer" , " answer" , " candidate" :
179186 h.forward (msg)
180187 default :
@@ -202,6 +209,7 @@ func (h *Hub) HandleWS(w http.ResponseWriter, r *http.Request) {
202209- 根据 ` msg.Type ` :
203210 - ` join ` :设置 ` client.id ` /` client.room ` ,并调用 ` addClient ` ;
204211 - ` leave ` :调用 ` removeClient ` ;
212+ - ` ping ` :可选心跳消息,服务端可回写 ` pong ` (非阻塞发送);
205213 - ` offer/answer/candidate ` :调用 ` forward(msg) ` ,根据房间和 ` To ` 转发;
206214 - 其他:打印未知类型日志。
207215
@@ -268,30 +276,33 @@ func (h *Hub) removeClient(c *Client) {
268276 if c.room == " " || c.id == " " {
269277 return
270278 }
271- if m , ok := h.rooms [c.room ]; ok {
272- if existing , ok2 := m[c.id ]; ok2 {
273- delete (m, c.id )
274- close (existing.send )
279+ room := c.room
280+ if m , ok := h.rooms [room]; ok {
281+ if _ , ok2 := m[c.id ]; !ok2 {
282+ c.room = " "
283+ return
275284 }
285+ delete (m, c.id )
286+ c.room = " "
276287 if len (m) == 0 {
277- delete (h.rooms , c. room )
278- log.Printf (" signal: room %s closed" , c. room )
279- } else {
280- members := make ([] string , 0 , len (m))
281- for id := range m {
282- members = append (members, id)
283- }
284- msg := Message{
285- Type: " room_members " ,
286- Room : c. room ,
287- Members: members ,
288- }
289- for _ , cli := range m {
290- if cli != nil && cli. conn != nil {
291- select {
292- case cli. send <- msg:
293- default :
294- }
288+ delete (h.rooms , room)
289+ log.Printf (" signal: room %s closed" , room)
290+ return
291+ }
292+ members := make ([] string , 0 , len (m))
293+ for id := range m {
294+ members = append (members, id)
295+ }
296+ msg := Message{
297+ Type : " room_members " ,
298+ Room: room ,
299+ Members: members,
300+ }
301+ for _ , cli := range m {
302+ if cli != nil && cli. conn != nil {
303+ select {
304+ case cli. send <- msg :
305+ default :
295306 }
296307 }
297308 }
@@ -302,10 +313,11 @@ func (h *Hub) removeClient(c *Client) {
302313关键点:
303314
304315- 同样通过互斥锁保护 ` rooms ` ;
305- - 找到 ` rooms[c. room] ` 后:
306- - 删除对应 ` id ` ,并关闭其 ` send ` 通道;
316+ - 找到 ` rooms[room] ` 后:
317+ - 删除对应 ` id ` (这里不关闭 ` send ` 通道, ` send ` 在 ` HandleWS ` 的 ` defer ` 中统一关闭,以结束 ` writePump ` ) ;
307318 - 若该房间已空,删除房间并打印“room closed”;
308319 - 若仍有其他成员:重新构建成员列表,广播 ` room_members ` 给房间内剩余成员。
320+ - 离开后将 ` c.room ` 置空,避免同一连接在 ` leave ` 后被 ` defer ` 再次 ` removeClient ` 时重复处理。
309321
310322> 注意:
311323> - 这里使用 ` select { case cli.send <- msg: default: } ` 非阻塞发送,避免因为某个客户端处理过慢而卡住整个 Hub。
0 commit comments