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

如何在Node.js中实现TCP套接字移交?游戏分布式服务器场景

Node.js 中 TCP 套接字移交至游戏服务器的实现方案

方案一:Unix/Linux 环境下的文件描述符传递(无缝接管)

这是最接近"移交套接字"原生需求的方案,依赖Unix系统的文件描述符传递能力,无需客户端重新连接。

  • 核心逻辑:认证服务器完成校验后,将客户端TCP套接字的文件描述符通过IPC通道(如Unix域套接字)发送给游戏服务器,游戏服务器用该描述符重建套接字实例,接管连接。

  • 实现步骤:

    1. 认证服务器获取客户端套接字的文件描述符:Node.js 10+ 可直接使用 socket.fd,低版本可访问内部属性 socket._handle.fd(注意内部属性可能随版本变化)。
    2. 通过Unix域套接字向游戏服务器传递描述符:利用 net.Socket 的 sendFD 方法(需确保IPC通道支持)。
    3. 游戏服务器接收描述符后,用 new net.Socket({ fd: 接收的描述符 }) 创建套接字,恢复数据监听。
  • 简化代码示例:
    认证服务器端:

    const net = require('net');
    
    // 启动IPC服务,用于和游戏服务器通信
    const ipcServer = net.createServer(ipcSocket => {
      // 处理客户端认证连接
      const authServer = net.createServer(clientSocket => {
        clientSocket.on('data', authData => {
          // 模拟认证成功逻辑
          const authSuccess = true;
          if (authSuccess) {
            // 发送移交信号+文件描述符
            ipcSocket.write(Buffer.from('TRANSFER'), err => {
              if (!err) {
                ipcSocket.sendFD(clientSocket.fd);
                clientSocket.unref(); // 认证服务器不再持有该套接字引用
              }
            });
          }
        });
      });
      authServer.listen(3000);
    });
    ipcServer.listen('/tmp/game_transfer.sock');
    

    游戏服务器端:

    const net = require('net');
    
    // 连接到认证服务器的IPC通道
    const ipcClient = net.connect('/tmp/game_transfer.sock');
    ipcClient.on('fd', fd => {
      // 用接收的文件描述符重建套接字
      const gameSocket = new net.Socket({ fd });
      gameSocket.on('data', gameData => {
        // 处理游戏业务逻辑
        gameSocket.write('已接入游戏服务器,开始交互');
      });
      gameSocket.resume(); // 恢复数据流动
    });
    

方案二:跨平台中转代理模式(兼容性优先)

如果需要支持Windows等不支持文件描述符传递的平台,推荐这种客户端重连方案,实现简单且跨平台。

  • 核心逻辑:认证完成后,认证服务器向客户端返回游戏服务器地址+临时会话令牌,客户端断开认证连接后,携带令牌连接游戏服务器,游戏服务器验证令牌有效性后建立游戏连接。

  • 优势:无平台限制,实现成本低;缺点是客户端需要重新发起连接,存在少量延迟。

  • 简化代码示例:
    认证服务器端(依赖Redis存储会话):

    const net = require('net');
    const redis = require('redis');
    const redisClient = redis.createClient();
    
    const authServer = net.createServer(async clientSocket => {
      clientSocket.on('data', async data => {
        const { username, password } = JSON.parse(data.toString());
        // 模拟认证校验
        if (username === 'player' && password === 'game123') {
          // 生成临时会话令牌,5分钟过期
          const sessionToken = `game_token_${Date.now()}`;
          await redisClient.setEx(sessionToken, 300, JSON.stringify({ username }));
          // 向客户端发送游戏服务器信息和令牌
          clientSocket.write(JSON.stringify({
            gameServer: { host: '127.0.0.1', port: 3001 },
            token: sessionToken
          }));
          clientSocket.end();
        }
      });
    });
    authServer.listen(3000);
    

    游戏服务器端:

    const net = require('net');
    const redis = require('redis');
    const redisClient = redis.createClient();
    
    const gameServer = net.createServer(async clientSocket => {
      clientSocket.on('data', async data => {
        const { token } = JSON.parse(data.toString());
        const userInfo = await redisClient.get(token);
        if (userInfo) {
          // 验证通过,删除令牌防止重复使用
          await redisClient.del(token);
          clientSocket.write('认证通过,进入游戏');
          // 处理游戏逻辑
        } else {
          clientSocket.write('无效会话令牌');
          clientSocket.end();
        }
      });
    });
    gameServer.listen(3001);
    

方案三:临时管道中转(过渡方案)

如果需要客户端无感知过渡,又不想依赖平台特性,可以用双向管道中转数据,直到游戏服务器确认接管。

  • 核心逻辑:认证服务器完成校验后,主动连接游戏服务器,将客户端套接字与游戏服务器的连接双向管道,实现数据中转,后续可根据业务逻辑决定何时断开中转。

  • 缺点:认证服务器会承担中转压力,不适合高并发场景。

  • 简化代码示例:

    // 认证服务器端
    const net = require('net');
    const authServer = net.createServer(clientSocket => {
      clientSocket.on('data', authData => {
        // 模拟认证成功
        if (true) {
          // 连接游戏服务器
          const gameConn = net.connect(3001, '127.0.0.1');
          // 双向管道数据
          clientSocket.pipe(gameConn);
          gameConn.pipe(clientSocket);
          // 告知游戏服务器客户端身份
          gameConn.write(JSON.stringify({ userId: 'player_1001' }));
        }
      });
    });
    authServer.listen(3000);
    

内容的提问来源于stack exchange,提问作者양성철

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:39:53