You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Socket.io房间中向双方展示已连接玩家的用户名

实现房间内两名玩家互相展示用户名的方案

首先,你的项目已经基于passport.js和express-sessions完成了身份认证,要实现实时展示彼此用户名的核心是引入实时通信机制(因为HTTP是请求响应式的,没法主动推送更新),这里推荐用Socket.io来实现,下面是具体的步骤和代码示例:

1. 集成Socket.io并共享Express Session

因为用户的登录信息存在express-sessions里,所以需要让Socket.io能访问到session数据,这样才能拿到当前连接用户的用户名。

服务器端配置(Express + Socket.io)

首先安装依赖:

npm install socket.io express-socket.io-session

然后修改你的Express启动文件:

const express = require('express');
const session = require('express-session');
const passport = require('passport');
const socketIo = require('socket.io');
const sharedSession = require('express-socket.io-session');

const app = express();
const server = require('http').createServer(app);
const io = socketIo(server);

// 你的session配置(和之前passport用的一致)
const sessionMiddleware = session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false,
  // 其他配置比如store等
});

// 应用session和passport中间件
app.use(sessionMiddleware);
app.use(passport.initialize());
app.use(passport.session());

// 让Socket.io共享Express的session
io.use(sharedSession(sessionMiddleware, {
  autoSave: true
}));

// 处理Socket连接
io.on('connection', (socket) => {
  // 检查用户是否登录(从session中获取)
  if (!socket.handshake.session.passport?.user) {
    socket.disconnect();
    return;
  }
  const currentUser = socket.handshake.session.passport.user; // 这里是你的用户对象,包含username等信息

  // 处理创建房间请求
  socket.on('createRoom', () => {
    const roomId = `room-${Date.now()}`; // 生成唯一房间ID
    socket.join(roomId);
    // 向当前用户发送房间ID和初始玩家信息
    socket.emit('roomJoined', {
      roomId,
      players: [currentUser.username]
    });
  });

  // 处理加入房间请求
  socket.on('joinRoom', (roomId) => {
    const room = io.sockets.adapter.rooms.get(roomId);
    // 检查房间是否存在且人数小于2
    if (!room || room.size >= 2) {
      socket.emit('joinFailed', '房间不存在或已满');
      return;
    }
    socket.join(roomId);
    // 获取房间内所有玩家的用户名
    const players = [];
    room.forEach(socketId => {
      const playerSocket = io.sockets.sockets.get(socketId);
      players.push(playerSocket.handshake.session.passport.user.username);
    });
    players.push(currentUser.username); // 加入当前用户
    // 向房间内所有用户推送更新后的玩家列表
    io.to(roomId).emit('playersUpdated', { players });
  });

  // 处理用户断开连接
  socket.on('disconnect', () => {
    // 遍历用户所在的所有房间
    socket.rooms.forEach(roomId => {
      if (roomId !== socket.id) { // 排除用户自身的socket ID房间
        const room = io.sockets.adapter.rooms.get(roomId);
        if (room && room.size > 0) {
          // 更新房间内玩家列表
          const players = [];
          room.forEach(socketId => {
            const playerSocket = io.sockets.sockets.get(socketId);
            if (playerSocket && playerSocket.handshake.session.passport?.user) {
              players.push(playerSocket.handshake.session.passport.user.username);
            }
          });
          // 通知剩余玩家更新列表
          io.to(roomId).emit('playersUpdated', { players });
        }
      }
    });
  });
});

// 启动服务器
server.listen(3000, () => {
  console.log('Server running on port 3000');
});

2. 前端页面逻辑

在你的首页(未启动游戏的页面)中,引入Socket.io客户端,并实现创建/加入房间的交互,以及监听玩家列表更新来渲染用户名:

<!DOCTYPE html>
<html>
<head>
  <title>游戏首页</title>
</head>
<body>
  <div>
    <button id="createRoomBtn">创建房间</button>
    <input type="text" id="roomIdInput" placeholder="输入房间ID">
    <button id="joinRoomBtn">加入房间</button>
  </div>
  <div id="playersContainer">
    <h3>房间玩家:</h3>
    <div id="player1"></div>
    <div id="player2"></div>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script>
    const socket = io();

    // 绑定创建房间按钮事件
    document.getElementById('createRoomBtn').addEventListener('click', () => {
      socket.emit('createRoom');
    });

    // 绑定加入房间按钮事件
    document.getElementById('joinRoomBtn').addEventListener('click', () => {
      const roomId = document.getElementById('roomIdInput').value.trim();
      if (roomId) {
        socket.emit('joinRoom', roomId);
      }
    });

    // 监听加入房间成功事件
    socket.on('roomJoined', (data) => {
      console.log('已加入房间:', data.roomId);
      // 渲染初始玩家(自己)
      document.getElementById('player1').textContent = `玩家1:${data.players[0]}`;
    });

    // 监听玩家列表更新事件
    socket.on('playersUpdated', (data) => {
      // 根据玩家数量渲染
      if (data.players.length >= 1) {
        document.getElementById('player1').textContent = `玩家1:${data.players[0]}`;
      }
      if (data.players.length >= 2) {
        document.getElementById('player2').textContent = `玩家2:${data.players[1]}`;
      } else {
        document.getElementById('player2').textContent = ''; // 清空第二个玩家位置
      }
    });

    // 监听加入失败事件
    socket.on('joinFailed', (msg) => {
      alert(msg);
    });
  </script>
</body>
</html>

3. 关键逻辑说明

  • Session共享:通过express-socket.io-session中间件,让Socket.io能访问到Express的session数据,从而获取当前登录用户的用户名。
  • 房间管理:利用Socket.io的房间(Room)功能,将同一房间的用户分组,方便向组内所有用户推送消息。
  • 实时同步:当有玩家加入/离开房间时,服务器主动向房间内所有用户推送更新后的玩家列表,前端收到后立即更新DOM,实现实时展示。

你可以根据自己的项目结构调整代码,比如用户对象的字段名(如果你的用户信息不是username,需要对应修改),还有房间ID的生成方式(可以用更友好的ID,比如短字符串)。

内容的提问来源于stack exchange,提问作者roh_dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:26:30