socket.to(room).emit()无法向房间内其他客户端推送事件排查
Socket.io中
socket.to(room).emit()在离开大厅时无法推送事件的原因 问题描述
我需要在客户端离开大厅(lobby)时通知房间内其他客户端,但使用socket.to(room).emit()方法未达到预期效果。客户端已实现加入他人大厅的逻辑,会发送"join-lobby"事件,服务端处理代码如下:
服务端处理"join-lobby"事件的代码
socket.on("join-lobby", (lobby, callback) => { // Check whether lobby exists let room = io.sockets.adapter.rooms.get(lobby) if (room === undefined) { callback(null); // send null to client } else { // Lobby exists socket.join(lobby); // Join another's lobby callback({ lobby }); // send lobby ID back to client } });
客户端也实现了离开大厅的逻辑,会发送"request-leave"事件,服务端处理代码如下:
服务端处理"request-leave"事件的代码(无效)
socket.on("request-leave", (lobby) => { socket.to(lobby).emit("leave-notify") });
此处socket.to(lobby).emit()无法向大厅内其他客户端发送"leave-notify"事件,且已确认大厅内存在其他在线客户端。
临时解决方案(有效)
手动遍历房间内客户端ID并单独推送事件,该方法可以正常工作:
socket.on("request-leave", (lobby) => { io.sockets.adapter.rooms.get(lobby).forEach(clientId => { if(clientId !== socket.id) io.to(clientId).emit("leave-notify") // this does work }); });
完整服务端代码
import { createServer } from "http"; import { Server } from "socket.io"; const port = 3000; const server = createServer(); const io = new Server(server, { cors: { origin: ["http://localhost:5173"], }, }); io.on("connection", (socket) => { console.log(`${socket.id} connected`); socket.emit("get-id", socket.id); socket.on("join-lobby", (lobby, callback) => { // Check whether lobby exists let room = io.sockets.adapter.rooms.get(lobby) if (room === undefined) { callback(null); } else { // Lobby exists socket.join(lobby); // Join another's lobby socket.to(lobby).emit("get-opponent", socket.id); // Notify other players in the lobby callback({ lobby }); } }); socket.on("request-leave", (lobby) => { socket.to(lobby).emit("leave-notify") }); // works // socket.on("request-leave", (lobby) => { // io.sockets.adapter.rooms.get(lobby).forEach(clientId => { // if(clientId !== socket.id) io.to(clientId).emit("leave-notify") // }) // }); socket.on("disconnect", () => { console.log(`${socket.id} disconnected`); }); }); server.listen(port, () => { console.log(`Server listening on port ${port}`); });
补充说明
奇怪的是,在socket.join(lobby)之后立即使用socket.to(<room-id>).emit()可以正常推送事件,示例如下:
socket.on("join-lobby", (lobby, callback) => { // Check whether lobby exists let room = io.sockets.adapter.rooms.get(lobby) if (room === undefined) { callback(null); // send null to client } else { // Lobby exists socket.join(lobby); // Join another's lobby socket.to(lobby).emit("get-opponent", socket.id); // This somehow works callback({ lobby }); // send lobby ID back to client } });
问题原因分析
核心问题是调用socket.to(lobby).emit()时,当前socket已经不在这个lobby房间里了。
socket.to(room).emit()的底层逻辑是:向指定房间内除当前socket自身之外的所有客户端发送事件,但这个方法生效的前提是,当前socket本身属于目标房间。如果当前socket已经被移除出lobby房间,socket.to(lobby)无法定位到有效的目标受众,自然无法发送事件。- 在"join-lobby"事件中,刚执行完
socket.join(lobby),当前socket确实属于该房间,所以socket.to(lobby)能正确找到房间内的其他客户端,推送事件有效。 - 临时解决方案之所以有效,是因为它直接通过
io.sockets.adapter.rooms.get(lobby)获取房间内的所有客户端ID,跳过当前socket后逐个定向推送,不依赖当前socket是否属于目标房间的状态,因此不受socket房间变更的影响。
内容的提问来源于stack exchange,提问作者aaditya-1219
相关产品推荐
相关产品推荐

