首页 > 语言 > JavaScript > 正文

Node.Js中实现端口重用原理详解

2024-05-06 15:34:41
字体:
来源:转载
供稿:网友

本文介绍了Node.Js中实现端口重用原理详解,分享给大家,具体如下:

起源,从官方实例中看多进程共用端口

const cluster = require('cluster');const http = require('http');const numCPUs = require('os').cpus().length;if (cluster.isMaster) { console.log(`Master ${process.pid} is running`); for (let i = 0; i < numCPUs; i++) {  cluster.fork(); } cluster.on('exit', (worker, code, signal) => {  console.log(`worker ${worker.process.pid} died`); });} else { http.createServer((req, res) => {  res.writeHead(200);  res.end('hello world/n'); }).listen(8000); console.log(`Worker ${process.pid} started`);}

执行结果:

$ node server.js
Master 3596 is running
Worker 4324 started
Worker 4520 started
Worker 6056 started
Worker 5644 started

了解http.js模块:

我们都只有要创建一个http服务,必须引用http模块,http模块最终会调用net.js实现网络服务

// lib/net.js'use strict'; ...Server.prototype.listen = function(...args) {  ... if (options instanceof TCP) {   this._handle = options;   this[async_id_symbol] = this._handle.getAsyncId();   listenInCluster(this, null, -1, -1, backlogFromArgs); // 注意这个方法调用了cluster模式下的处理办法   return this;  }  ...};function listenInCluster(server, address, port, addressType,backlog, fd, exclusive) {// 如果是master 进程或者没有开启cluster模式直接启动listenif (cluster.isMaster || exclusive) {  //_listen2,细心的人一定会发现为什么是listen2而不直接使用listen // _listen2 包裹了listen方法,如果是Worker进程,会调用被hack后的listen方法,从而避免出错端口被占用的错误  server._listen2(address, port, addressType, backlog, fd);  return; } const serverQuery = {  address: address,  port: port,  addressType: addressType,  fd: fd,  flags: 0 };// 是fork 出来的进程,获取master上的handel,并且监听,// 现在是不是很好奇_getServer方法做了什么 cluster._getServer(server, serverQuery, listenOnMasterHandle);} ...

答案很快就可以通过cluster._getServer 这个函数找到

    代理了server._listen2 这个方法在work进程的执行操作 向master发送queryServer消息,向master注册一个内部TCP服务器
// lib/internal/cluster/child.jscluster._getServer = function(obj, options, cb) { // ... const message = util._extend({  act: 'queryServer',  // 关键点:构建一个queryServer的消息  index: indexes[indexesKey],  data: null }, options); message.address = address;// 发送queryServer消息给master进程,master 在收到这个消息后,会创建一个开始一个server,并且listen send(message, (reply, handle) => {   rr(reply, indexesKey, cb);       // Round-robin. }); obj.once('listening', () => {  cluster.worker.state = 'listening';  const address = obj.address();  message.act = 'listening';  message.port = address && address.port || options.port;  send(message); });}; //... // Round-robin. Master distributes handles across workers.function rr(message, indexesKey, cb) {  if (message.errno) return cb(message.errno, null);  var key = message.key;  // 这里hack 了listen方法  // 子进程调用的listen方法,就是这个,直接返回0,所以不会报端口被占用的错误  function listen(backlog) {    return 0;  }  // ...  const handle = { close, listen, ref: noop, unref: noop };  handles[key] = handle;  // 这个cb 函数是net.js 中的listenOnMasterHandle 方法  cb(0, handle);}// lib/net.js/*function listenOnMasterHandle(err, handle) {  err = checkBindError(err, port, handle);  server._handle = handle;  // _listen2 函数中,调用的handle.listen方法,也就是上面被hack的listen  server._listen2(address, port, addressType, backlog, fd); }*/            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选