这里有一个例子: https://github.com/websockets/ws/issues/154
在父级中我们有:
const cp = require('child_process');
const http = require('http');
const child = cp.fork('child.js');
const server = http.createServer();
server.on('upgrade', (request, socket) => {
child.send({ headers: request.headers, method: request.method }, socket);
});
server.listen(8080);
在子进程中我们有:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ noServer: true });
process.on('message', (request, socket) => {
wss.handleUpgrade(request, socket, undefined, (ws) => {
ws.send('foo');
});
});
我的问题:对于我的用例,我希望在父进程中使用 websocket 服务器,但允许子进程直接写入 WSS 连接的套接字,这可能吗?
虽然至少在 UNIX 系统上可以使用 IPC 向另一个进程发送普通 TCP 套接字,但对于 WSS 所需的 TLS 连接来说这是不可能的。这是因为 TLS 状态位于已完成 TLS 握手的进程的用户空间内。该状态不能简单地序列化并传输到另一个进程,因为它使用指向父进程内存的指针与 SSL 库中的各种结构交织在一起。
如果 TLS 不是在 Nodejs 中终止,而是(通常)在 Nodejs 前面的某些反向代理中终止,那么只需处理纯 TCP,在这种情况下,将套接字传播到另一个进程并在该进程内进行 Websockets 握手是可行的。
Node.js 集群模块允许您在服务器进程中监听,但有一个工作(子)进程处理通信。
在集群模式下,您在工作进程中调用
createServer()
,但 Node.js 实际上会在主进程中创建监听套接字。当客户端连接时,套接字将被转移到工作进程以进一步处理通信。 Node.js 使用循环方法来选择下一个工作人员。
在主进程中,您可以使用
cluster.fork()
创建新的工作进程。这最终会调用 child_process.fork()
。
通常您会创建固定数量的工作进程,例如每个 CPU 核心一个工作进程。但您可以根据需要创建和销毁工作进程。
希望这对您有帮助。
当您在工作线程中调用 server.listen(...) 时,它会序列化 参数并将请求传递给主进程。如果大师 进程已经有一个与工作进程匹配的监听服务器 要求,然后将句柄传递给工作人员。如果没有 已经有一个符合该要求的监听服务器,那么它 将创建一个,并将句柄传递给子级。
在node.js中,通过ws lib,Net.Socket、Http.Server和WebSocket.Server可以像乐高积木一样相互构建,并且可以在协议层次结构的每个级别上处理数据包:
server = http.createServer(handleHTTPLevel);
wss = new WSS({ server });
wss.on('connection', handleWSLevel);
netServer = net.createServer(function (socket){
handleTCPLevel(socket)
server.emit('connection', socket);
}).listen( listenPort );
但是只有 Net.Socket 可以传输给子进程,因此,在子进程中还应该构建一个 HTTP 和 WebSocket 服务器来处理 Net.Socket
如果您想要处理 TLS/SSL 连接,您应该在父进程中也作为 Net.Server 进行监听,在连接上将 Net.Socket 传输给子进程,并在 HTTPS 服务器实例上发出“连接”事件,使用从文件加载或从父进程接收的证书和密钥构造。
注意,在这样的架构中,你将无法在主进程中处理来自新连接的数据,而只能接受新连接并立即将新的 Net.Socket 传输给子进程,因此,握手逻辑应该放在它。
理论上,在 TLS/SSL 的情况下,您可以在不同的子进程中使用不同的证书