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

三层架构Express Node应用中WebSockets(Socket.io)部署位置咨询

基于TypeSocket.io的Express三层架构整合方案

你的网关抽象层思路完全正确,核心是通过解耦让应用层彻底脱离对Socket.io这类具体网络实现的依赖,只依赖抽象接口完成双向通信。下面是落地的架构设计、代码示例和模式建议:

核心架构分层逻辑

保持原有的三层结构,新增网关抽象层作为网络层与应用层的双向桥梁:

  • 网络/路由控制层:负责Socket.io的初始化、连接管理、事件监听/转发,是网关的具体实现载体
  • 网关抽象层:定义标准化的双向通信接口,隔离应用层与网络实现细节
  • 应用/服务层:游戏引擎依赖网关抽象接口,处理客户端动作并主动推送游戏状态
  • 数据存储层:负责游戏状态的持久化,与WebSocket逻辑完全解耦

TypeScript代码示例

1. 网关抽象层(定义接口)

// src/gateway/game.gateway.ts
import { EventEmitter } from 'events';

// 客户端动作类型定义
export type PlayerAction = {
  playerId: string;
  actionType: 'move' | 'attack' | 'joinRoom';
  payload: Record<string, any>;
};

// 应用层只依赖这个抽象接口
export interface IGameGateway {
  // 订阅客户端动作事件
  onPlayerAction(callback: (action: PlayerAction) => void): void;
  // 推送游戏状态给单个玩家
  pushToPlayer(playerId: string, event: string, data: any): void;
  // 广播游戏状态给房间内所有玩家
  broadcastToRoom(roomId: string, event: string, data: any): void;
}

// Socket.io实现的网关具体类(放在网络层)
export class SocketGameGateway extends EventEmitter implements IGameGateway {
  private io: SocketIO.Server;

  constructor(io: SocketIO.Server) {
    super();
    this.io = io;
    this.setupSocketHandlers();
  }

  private setupSocketHandlers() {
    this.io.on('connection', (socket) => {
      // 处理客户端身份验证(示例:从query获取playerId)
      socket.data.playerId = socket.handshake.query.playerId as string;
      socket.join(socket.handshake.query.roomId as string);

      // 转发客户端动作到应用层
      socket.on('player-action', (action: PlayerAction) => {
        this.emit('player-action', action);
      });

      // 转发断开连接事件
      socket.on('disconnect', () => {
        this.emit('player-disconnect', socket.data.playerId);
      });
    });
  }

  onPlayerAction(callback: (action: PlayerAction) => void): void {
    this.on('player-action', callback);
  }

  pushToPlayer(playerId: string, event: string, data: any): void {
    this.io.to(playerId).emit(event, data);
  }

  broadcastToRoom(roomId: string, event: string, data: any): void {
    this.io.to(roomId).emit(event, data);
  }
}

2. 应用/服务层(游戏引擎)

// src/service/game.engine.ts
import { IGameGateway, PlayerAction } from '../gateway/game.gateway';

export class GameEngine {
  private roomStates: Record<string, any> = {};
  private gateway: IGameGateway;

  constructor(gateway: IGameGateway) {
    this.gateway = gateway;
    // 订阅网关传来的客户端动作
    this.gateway.onPlayerAction((action) => this.handlePlayerAction(action));
    // 定时更新游戏状态(模拟实时逻辑)
    setInterval(() => this.syncRoomStates(), 100);
  }

  private handlePlayerAction(action: PlayerAction) {
    const roomId = this.getPlayerRoom(action.playerId);
    if (!this.roomStates[roomId]) return;

    // 执行游戏核心逻辑
    switch (action.actionType) {
      case 'move':
        this.roomStates[roomId].players[action.playerId].position = action.payload.position;
        break;
      case 'attack':
        this.roomStates[roomId].players[action.playerId].attackCount++;
        break;
    }
  }

  private syncRoomStates() {
    // 遍历所有房间,推送最新状态
    Object.keys(this.roomStates).forEach(roomId => {
      this.gateway.broadcastToRoom(roomId, 'game-state', this.roomStates[roomId]);
    });
  }

  private getPlayerRoom(playerId: string): string {
    // 从存储层获取玩家所在房间(示例逻辑)
    return 'room-1';
  }
}

3. 网络层(Express + Socket.io初始化)

// src/server.ts
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';
import { SocketGameGateway } from './gateway/game.gateway';
import { GameEngine } from './service/game.engine';

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
  cors: { origin: ['https://your-client-domain.com'] }
});

// 初始化网关与游戏引擎(依赖注入)
const gameGateway = new SocketGameGateway(io);
const gameEngine = new GameEngine(gameGateway);

// 普通REST路由示例
app.get('/api/rooms', (req, res) => {
  res.json(Object.keys(gameEngine['roomStates']));
});

httpServer.listen(3000, () => {
  console.log('Server running on port 3000');
});

关键设计模式建议

  1. 依赖倒置原则:应用层只依赖IGameGateway抽象接口,不直接接触Socket.io。后续如果替换为ws或其他WebSocket库,只需新增对应网关实现类,无需修改游戏引擎代码。
  2. 观察者模式:网关通过EventEmitter实现事件转发,应用层订阅事件即可处理客户端动作,完全解耦发送者与接收者。
  3. 端口与适配器模式(六边形架构):将网关视为应用层的"输入/输出端口",SocketGameGateway是适配Socket.io的适配器,让应用核心逻辑与外部网络实现彻底隔离。

注意事项

  • 网络层负责Socket的连接验证、房间管理、错误处理等与传输相关的逻辑,应用层只关心游戏规则。
  • 避免在应用层中直接操作Socket实例,所有网络交互必须通过网关接口完成。
  • 可以扩展网关接口,增加如onPlayerDisconnect、pushToAll等方法,满足不同业务场景需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 21:31:12