Node.js uWS.js多线程服务器仅单一路径可连接问题
问题根源
- Windows的TCP端口绑定机制和类Unix系统不同,默认不允许多个线程/进程同时抢占同一个端口。即便你看到两个线程都输出“监听成功”,实际上只有第一个完成端口绑定的线程能接收所有请求,它只配置了对应自身
threadId的WebSocket路径,所以其他路径的连接请求会被直接拒绝。 - uWS在Windows下不支持
SO_REUSEPORT(类Unix系统的端口复用特性),因此多线程绑定同端口的写法在Windows上本质是无效的。
可行解决方案
方案1:主进程统一监听,分发请求到子线程
把端口监听逻辑放在主进程,在主进程中配置所有WebSocket路径,再将对应路径的请求转发给子线程处理:
主进程代码:
const uWS = require('uWebSockets.js'); const port = 3000; const { Worker } = require('worker_threads'); // 创建两个子线程,传递线程ID const workerMap = { 1: new Worker('./worker.js', { workerData: { threadId: 1 } }), 2: new Worker('./worker.js', { workerData: { threadId: 2 } }) }; // 主进程监听端口,配置全路径WebSocket路由 uWS.App() .ws('/1', { open: (ws) => { console.log('将/1路径的连接交给线程1处理'); // 注意:uWS的ws对象无法直接序列化传给子线程,需在主进程做消息转发 ws.on('message', (msg) => { workerMap[1].postMessage({ type: 'message', data: msg }); }); } }) .ws('/2', { open: (ws) => { console.log('将/2路径的连接交给线程2处理'); ws.on('message', (msg) => { workerMap[2].postMessage({ type: 'message', data: msg }); }); } }) .listen(port, (token) => { token ? console.log(`主进程监听端口${port}成功`) : console.log(`主进程监听端口${port}失败`); });
子线程文件worker.js:
const { parentPort, workerData } = require('worker_threads'); parentPort.on('message', (msg) => { if (msg.type === 'message') { console.log(`线程${workerData.threadId}收到消息:${msg.data}`); // 此处编写具体业务处理逻辑 } });
方案2:子线程监听不同端口(Windows快速验证用)
给每个子线程分配不同的端口,客户端直接连接对应端口的路径:
const uWS = require('uWebSockets.js'); const { Worker, isMainThread, workerData } = require('worker_threads'); if (isMainThread) { // 启动两个子线程,分别监听3001、3002端口 [1,2].forEach(id => new Worker(__filename, { workerData: { port: 3000 + id, threadId: id } })); } else { const { port, threadId } = workerData; const wsPath = `/${threadId}`; uWS.App().ws(wsPath, { open: () => console.log(`线程${threadId}的WebSocket连接建立成功`), }).listen(port, (token) => { token ? console.log(`线程${threadId}监听端口${port}成功`) : console.log(`线程${threadId}监听端口${port}失败`); }); }
客户端分别连接localhost:3001/1和localhost:3002/2即可。
方案3:切换到类Unix系统(Linux/macOS)
如果可以切换到Linux或macOS,uWS原生支持SO_REUSEPORT,直接用内置多线程模式即可:
const uWS = require('uWebSockets.js'); const port = 3000; const os = require('os'); uWS.App() .ws('/1', { open: () => console.log(`连接到线程:${process.pid}`) }) .ws('/2', { open: () => console.log(`连接到线程:${process.pid}`) }) // 指定线程数,uWS自动创建多线程监听同端口 .listen(port, os.cpus().length, (token) => { token ? console.log(`监听端口${port}成功`) : console.log(`监听端口${port}失败`); });
内容的提问来源于stack exchange,提问作者Serum0017
相关产品推荐
相关产品推荐

