Node.js如何让fork子进程的http服务处理主进程传递的socket连接
问题原因
你对server.listen()方法的使用场景理解错误:该方法的作用是让HTTP服务器启动监听状态,等待新的入站TCP连接。但主进程传递给子进程的是已经完成三次握手的已建立连接的Socket实例,不需要再走监听逻辑,直接传给HTTP服务器处理即可,调用listen自然会抛出参数无效的错误。
调整方案
主进程修改
你需要先解析请求头中的Cookie,匹配到对应用户的子进程后再传递Socket,避免错发进程:
const net = require("net"); const child_process = require("child_process"); const { parse } = require('querystring'); // 用户ID和对应子进程的映射表 const userWorkerMap = new Map(); const server = net.createServer({ pauseOnConnect: true }) server.on("connection", function(socket) { let headerBuf = ''; const readHeader = (chunk) => { headerBuf += chunk.toString(); // 检测到HTTP请求头结束标识 if (headerBuf.includes('\r\n\r\n')) { socket.removeListener('data', readHeader); // 解析Cookie获取用户标识 const cookieStr = headerBuf.match(/Cookie: (.*)\r\n/)?.[1] || ''; const cookies = parse(cookieStr, '; '); // 替换为你实际用来标识授权用户的Cookie字段 const userId = cookies.user_id || 'anonymous'; // 该用户没有对应子进程则新建 if (!userWorkerMap.has(userId)) { const worker = child_process.fork("worker.js"); worker.on('exit', () => userWorkerMap.delete(userId)); userWorkerMap.set(userId, worker); } // 传递Socket到对应用户的子进程 userWorkerMap.get(userId).send('socket', socket); } } socket.on('data', readHeader); }) server.listen(8080)
子进程修改
直接触发HTTP服务器的connection事件处理已建立的Socket即可,不需要调用listen:
const http = require("http"); const server = http.createServer(function(req, res) { // 此处写你的业务逻辑 res.end(`Processed by worker ${process.pid}`); }) process.on("message", function(msg, socket) { if (msg === 'socket' && socket) { // 把已建立的Socket交给HTTP服务处理 server.emit('connection', socket); // 恢复Socket的数据读取(主进程开了pauseOnConnect) socket.resume(); } })
注意事项
- 可根据实际业务需要增加子进程空闲回收逻辑,避免长时间无访问的子进程占用系统资源
- 子进程异常退出时需做好兜底处理,避免用户请求长时间挂起
- 如果需要支持HTTPS,可在主进程统一完成SSL握手后再传递Socket,无需修改子进程逻辑
内容的提问来源于stack exchange,提问作者Slee Woo
相关产品推荐
相关产品推荐

