亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

Node.Js中實現端口重用原理詳解

2024-05-06 16:44:03
字體:
來源:轉載
供稿:網友

本文介紹了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 這個函數找到

  1. 代理了server._listen2 這個方法在work進程的執行操作
  2. 向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); }*/

master進程收到queryServer消息后進行啟動服務

  1. 如果地址沒被監聽過,通過RoundRobinHandle監聽開啟服務
  2. 如果地址已經被監聽,直接綁定handel到已經監聽到服務上,去消費請求
// lib/internal/cluster/master.jsfunction queryServer(worker, message) {  const args = [    message.address,    message.port,    message.addressType,    message.fd,    message.index  ];  const key = args.join(':');  var handle = handles[key];  // 如果地址沒被監聽過,通過RoundRobinHandle監聽開啟服務  if (handle === undefined) {    var constructor = RoundRobinHandle;    if (schedulingPolicy !== SCHED_RR ||      message.addressType === 'udp4' ||      message.addressType === 'udp6') {      constructor = SharedHandle;    }    handles[key] = handle = new constructor(key,      address,      message.port,      message.addressType,      message.fd,      message.flags);  }  // 如果地址已經被監聽,直接綁定handel到已經監聽到服務上,去消費請求  // Set custom server data  handle.add(worker, (errno, reply, handle) => {    reply = util._extend({      errno: errno,      key: key,      ack: message.seq,      data: handles[key].data    }, reply);    if (errno)      delete handles[key]; // Gives other workers a chance to retry.    send(worker, reply, handle);  });}

看到這一步,已經很明顯,我們知道了多進行端口共享的實現原理

  1. 其實端口僅由master進程中的內部TCP服務器監聽了一次
  2. 因為net.js 模塊中會判斷當前的進程是master還是Worker進程
  3. 如果是Worker進程調用cluster._getServer 去hack原生的listen 方法
  4. 所以在child調用的listen方法,是一個return 0 的空方法,所以不會報端口占用錯誤

那現在問題來了,既然Worker進程是如何獲取到master進程監聽服務接收到的connect呢?

  1. 監聽master進程啟動的TCP服務器的connection事件
  2. 通過輪詢挑選出一個worker
  3. 向其發送newconn內部消息,消息體中包含了客戶端句柄
  4. 有了句柄,誰都知道要怎么處理了哈哈
// lib/internal/cluster/round_robin_handle.jsfunction RoundRobinHandle(key, address, port, addressType, fd) {  this.server = net.createServer(assert.fail);  if (fd >= 0)    this.server.listen({ fd });  else if (port >= 0)    this.server.listen(port, address);  else    this.server.listen(address); // UNIX socket path.  this.server.once('listening', () => {    this.handle = this.server._handle;    // 監聽onconnection方法    this.handle.onconnection = (err, handle) => this.distribute(err, handle);    this.server._handle = null;    this.server = null;  });}RoundRobinHandle.prototype.add = function (worker, send) {  // ...};RoundRobinHandle.prototype.remove = function (worker) {  // ...};RoundRobinHandle.prototype.distribute = function (err, handle) {  // 負載均衡地挑選出一個worker  this.handles.push(handle);  const worker = this.free.shift();  if (worker) this.handoff(worker);};RoundRobinHandle.prototype.handoff = function (worker) {  const handle = this.handles.shift();  const message = { act: 'newconn', key: this.key };  // 向work進程其發送newconn內部消息和客戶端的句柄handle  sendHelper(worker.process, message, handle, (reply) => {  // ...    this.handoff(worker);  });};

下面讓我們看看Worker進程接收到newconn消息后進行了哪些操作

// lib/child.jsfunction onmessage(message, handle) {  if (message.act === 'newconn')   onconnection(message, handle);  else if (message.act === 'disconnect')   _disconnect.call(worker, true); }// Round-robin connection.// 接收連接,并且處理function onconnection(message, handle) { const key = message.key; const server = handles[key]; const accepted = server !== undefined; send({ ack: message.seq, accepted }); if (accepted) server.onconnection(0, handle);}

總結

  1. net模塊會對進程進行判斷,是worker 還是master, 是worker的話進行hack net.Server實例的listen方法
  2. worker 調用的listen 方法是hack掉的,直接return 0,不過會向master注冊一個connection接手的事件
  3. master 收到客戶端connection事件后,會輪詢向worker發送connection上來的客戶端句柄
  4. worker收到master發送過來客戶端的句柄,這時候就可以處理客戶端請求了

分享出于共享學習的目的,如有錯誤,歡迎大家留言指導,不喜勿噴。也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
中文字幕一区日韩电影| 少妇激情综合网| 欧美成人自拍视频| 久久福利视频导航| 日韩av快播网址| 日韩精品极品在线观看播放免费视频| 午夜精品蜜臀一区二区三区免费| 91高清视频在线免费观看| 2023亚洲男人天堂| 日韩精品在线影院| 久久亚洲国产精品| 96精品视频在线| 国产精品日韩精品| 57pao国产成人免费| 国产精品户外野外| 国产精品视频一区二区高潮| 正在播放欧美视频| 国产精品视频一区二区三区四| 最近中文字幕mv在线一区二区三区四区| 欧美在线视频免费播放| 欧美日韩在线视频观看| 国产精品视频一区二区高潮| 国产精品久久久91| 欧美精品在线免费| 亚洲高清av在线| 日韩国产欧美区| 日韩在线视频免费观看| 亚洲欧美综合区自拍另类| 日韩欧美高清在线视频| 久久人人爽人人| 日本高清不卡在线| 黑人极品videos精品欧美裸| 欧美日韩国产在线看| 国产成人精品视| 黑人与娇小精品av专区| 欧美色道久久88综合亚洲精品| 亚洲18私人小影院| 国产精品第2页| 日韩中文字幕在线播放| 亚洲精品www久久久| 亚洲精品98久久久久久中文字幕| 亚洲free性xxxx护士hd| 亚洲91精品在线观看| 国产欧美精品一区二区| 精品国产一区二区三区久久狼黑人| 欧美性xxxxx| 91色视频在线导航| 国产欧美一区二区白浆黑人| 色偷偷偷亚洲综合网另类| 欧美一级淫片丝袜脚交| 国产亚洲日本欧美韩国| 亚洲免费人成在线视频观看| 亚洲级视频在线观看免费1级| 国产一区二区三区在线看| 亚洲成人精品视频在线观看| 国产精品一区二区久久精品| 中文字幕无线精品亚洲乱码一区| 欧美国产精品日韩| 91精品啪在线观看麻豆免费| 国产69精品99久久久久久宅男| 日韩在线观看免费全| 亚洲国产福利在线| 性色av一区二区三区免费| 伊人久久久久久久久久久| 国产丝袜一区视频在线观看| 91在线免费观看网站| 欧美成人精品影院| 丁香五六月婷婷久久激情| 美女精品视频一区| 精品成人久久av| 亚洲欧洲日产国码av系列天堂| 91天堂在线观看| 亚洲国产精品视频在线观看| 成人激情免费在线| 国产精品三级网站| 国产精品盗摄久久久| 欧美大片va欧美在线播放| 国产成人综合久久| 国产在线高清精品| 91九色在线视频| 国产欧美日韩丝袜精品一区| 亚洲人成电影网站色…| 国产精品毛片a∨一区二区三区|国| 亚洲欧美精品一区二区| 成人在线中文字幕| 亚洲精品乱码久久久久久按摩观| 精品日本高清在线播放| 另类色图亚洲色图| 欧美午夜激情在线| 欧美黑人国产人伦爽爽爽| 国产香蕉精品视频一区二区三区| www高清在线视频日韩欧美| 色综合久久天天综线观看| 精品一区二区三区四区在线| 亚洲高清福利视频| 亚洲成成品网站| 国产国语刺激对白av不卡| 欧美性视频在线| 国产亚洲精品久久久久动| 91啪国产在线| 欧美成人午夜激情视频| 国产偷国产偷亚洲清高网站| 欧美超级乱淫片喷水| 国产精品黄页免费高清在线观看| 国产精品爽爽ⅴa在线观看| 国产91在线高潮白浆在线观看| 亚洲无亚洲人成网站77777| 一区二区av在线| 亚洲激情视频在线| 国产精品久久久久久搜索| 国产欧美精品一区二区三区-老狼| 麻豆国产精品va在线观看不卡| 日韩成人在线免费观看| 亚洲高清福利视频| 国产欧美在线视频| 亚洲社区在线观看| 欧美在线视频免费| 成人免费大片黄在线播放| 色婷婷久久av| 亚洲国产精彩中文乱码av| 91在线视频成人| 欧美一级淫片aaaaaaa视频| 热99精品里视频精品| 中文字幕精品www乱入免费视频| 91视频九色网站| 国产啪精品视频| 国产成人久久久| 亚洲精品中文字幕av| 在线丨暗呦小u女国产精品| 国产亚洲精品一区二区| 国产视频综合在线| 日韩免费av在线| 亚洲最大成人在线| 亚洲国产日韩欧美在线动漫| 69久久夜色精品国产7777| 2020欧美日韩在线视频| 国产香蕉精品视频一区二区三区| 精品国产福利在线| 国产精品白丝av嫩草影院| 国产精品成人一区| 久久免费视频在线| 成人免费淫片aa视频免费| 青青精品视频播放| 欧美尺度大的性做爰视频| 亚洲视频日韩精品| 国产精品男女猛烈高潮激情| 成人做爽爽免费视频| 午夜精品一区二区三区在线播放| 亚洲一区第一页| 国产成人福利视频| 美日韩在线视频| 色综合色综合网色综合| 欧美亚洲国产视频| 在线亚洲国产精品网| 97精品国产91久久久久久| 一区二区三区黄色| 成人性生交大片免费观看嘿嘿视频| 疯狂欧美牲乱大交777| 欧洲s码亚洲m码精品一区| 国产精品久久久久av免费| 国产精品视频白浆免费视频| 日韩精品欧美国产精品忘忧草| 美女av一区二区三区| 深夜精品寂寞黄网站在线观看|