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

如何将Socket.io+Express+Phaser游戏从本地连接转为公网IP连接?

公网访问本地Socket.io游戏服务器的配置指南

问题背景

开发浏览器在线游戏,无需域名或云托管,希望本地运行服务器实现外网设备通过浏览器连接游玩。使用socket-io、express和Phaser开发,本地多标签页多人功能正常,但公网访问配置受阻。

核心代码

根目录server.js

const server = require('express')();
const http = require('http').createServer(server);
const host = 'localhost'; const port = 3000;

const io = require('socket.io')(http, {
    cors: { origin: `http://${host}:8080` }
  });

  io.on('connection', function (socket) {
      console.log('A user connected: ' + socket.id);
      socket.on('disconnect', function () { console.log('A user disconnected: ' + socket.id); });
  });

  http.listen(port, host, function () {
    console.log('Server started!');
});

客户端game.js

import io from 'socket.io-client';

const hostname = 'localhost'; const port = 3000;
let serverAddress = `http://${hostname}:${port}`;

export default class Game extends Phaser.Scene {
    constructor() {
        super({ key: 'Game' });
    }

    create() {
        this.socket = io(serverAddress);
        this.socket.on('connect', function () { console.log('Connected!'); });
    }
}

当前测试状态

  • 本地分别在根目录、客户端目录运行npm start,浏览器打开http://localhost:8080/时,服务器与客户端均显示连接成功。
  • 已在调制解调器设置端口3000(TCP+UDP)转发至本地IP 10.0.0.58,但外网设备无法连接。
  • 尝试将代码中localhost替换为公网静态IP xxx.xxx.xxx.234,server.js的http.listen()报错,关闭Windows Defender防火墙仍无效。外网设备输入各类地址均无法连接。

疑问解答与修改方案

1. 端口与服务的关系

  • 8080端口:是客户端静态资源服务器的端口(客户端目录npm start启动的服务,托管游戏前端文件如index.html、game.js),因此浏览器必须访问这个端口才能加载游戏页面。
  • 3000端口:是Socket.io后端服务器的端口(根目录server.js启动的express+socket.io服务),负责处理实时通信逻辑,前端页面加载后通过此端口建立socket连接。

这就是本地能通过xxx.xxx.xxx.234:8080加载游戏,但xxx.xxx.xxx.234:3000不行的原因——3000端口仅处理socket通信,不托管静态页面;CORS配置中的8080是允许前端资源服务器跨域请求socket服务。

2. 代码修改步骤

修改server.js

const server = require('express')();
const http = require('http').createServer(server);
const host = '0.0.0.0'; // 改为监听所有网络接口,而非仅localhost
const port = 3000;

const io = require('socket.io')(http, {
    cors: { origin: "*", methods: ["GET", "POST"] } // 开发阶段允许所有来源,上线后可限制特定IP
});

io.on('connection', function (socket) {
    console.log('A user connected: ' + socket.id);
    socket.on('disconnect', function () { console.log('A user disconnected: ' + socket.id); });
});

http.listen(port, host, function () {
    console.log(`Server running on http://${host}:${port}`);
});
  • 不要直接将host设为公网IP,公网IP属于路由器而非本地网卡,监听0.0.0.0可覆盖所有可用接口。

修改客户端game.js

import io from 'socket.io-client';

const hostname = 'xxx.xxx.xxx.234'; // 替换为你的公网静态IP
const port = 3000;
let serverAddress = `http://${hostname}:${port}`;

export default class Game extends Phaser.Scene {
    constructor() {
        super({ key: 'Game' });
    }

    create() {
        this.socket = io(serverAddress);
        this.socket.on('connect', function () { console.log('Connected!'); });
        // 添加错误监听方便排查问题
        this.socket.on('connect_error', (err) => {
            console.error('Connection error:', err);
        });
    }
}

3. 网络配置补充

  • 端口转发:路由器需同时转发两个端口:
    • 8080端口(TCP)→ 本地IP 10.0.0.58:8080
    • 3000端口(TCP+UDP)→ 本地IP 10.0.0.58:3000
    • 建议在路由器中给本地电脑设置静态IP绑定,避免重启后IP变化导致转发失效。
  • 防火墙设置:确保Windows防火墙允许Node.js程序通过,或临时关闭防火墙测试(测试通过后添加规则)。若8080端口被运营商屏蔽,可更换为不常用端口(如8081),同步修改客户端服务配置与路由器转发规则。

4. 外网访问方式

外网设备需在浏览器输入:http://xxx.xxx.xxx.234:8080

  • 该地址加载游戏前端页面,页面自动通过http://xxx.xxx.xxx.234:3000与Socket.io服务器建立连接。

排查技巧

  • 若外网能打开8080页面但无法连接socket:用在线工具检测3000端口是否开放,或在本地运行telnet xxx.xxx.xxx.234 3000验证端口连通性。
  • 若server.js启动报错:用netstat -ano | findstr :3000查看端口占用进程,关闭后重新启动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:27:50