찾다
웹 프론트엔드JS 튜토리얼Node.Js에서 포트 재사용 기능을 구현하는 방법

이번에는 Node.Js에서 포트 재사용 기능을 구현하는 방법과 Node.Js에서 포트 재사용 기능을 구현하기 위한 주의사항에 대해 알아보겠습니다.

Origin, 공식 인스턴스에서 다중 프로세스 공유 포트를 확인하세요

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  {
  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이 실행 중입니다
Worker 4324가 시작되었습니다
Worker 4520이 시작되었습니다
Worker 6056이 시작되었습니다
Worker 5644가 시작되었습니다

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模式直接启动listen
if (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. 및 Proxy server._listen2를 찾을 수 있습니다. 이 메소드는 작업 프로세스에서 작업을 수행하며

  2. 마스터에 queryServer 메시지를 보내고 마스터에 내부 TCP 서버를 등록합니다.

    // lib/internal/cluster/child.js
    cluster._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);
     }
    */
  3. 마스터 프로세스는 queryServer 메시지를 받은 후 서비스를 시작합니다.

    주소가 모니터링되지 않은 경우 RoundRobinHandle 모니터링을 통해 서비스를 시작합니다.
  1. 주소가 모니터링된 경우 핸들을 직접 바인딩합니다. 모니터링된 서비스를 실행하고 요청을 소비하러 갑니다
  2. // lib/internal/cluster/master.js
    function 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);
      });
    }
  3. 이 단계를 보면 다중 포트 공유의 구현 원리를 이미 알고 있음이 분명합니다

    실제로 포트는 내부 TCP에 의해 한 번만 수신됩니다. 서버는 마스터 프로세스에 있습니다
  1. net.js 모듈은 현재 프로세스가 마스터인지 아니면 작업자 프로세스인지를 결정하기 때문입니다
  2. 작업자 프로세스가 Cluster._getServer를 호출하면 기본 수신 방법을 해킹하세요
  3. 하위 항목에서 호출된 Listen 메서드는 0을 반환하는 빈 메서드이므로 포트 점유 오류가 보고되지 않습니다.
  4. 이제 질문이 뜹니다. 작업자 프로세스는 마스터 프로세스에서 받은 연결을 어떻게 얻나요? 청취 서비스?

    마스터 프로세스에 의해 시작된 TCP 서버의 연결
  1. 이벤트를 듣고

  2. 폴링을 통해 작업자를 선택하고
  3. 메시지 본문에 클라이언트 핸들
  4. 이 포함되어 있습니다.

  5. 핸들을 사용하면 무엇을 해야 할지 모두가 알 수 있습니다. 하하
  6. // lib/internal/cluster/round_robin_handle.js
    function 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);
      });
    };
  7. newconn 메시지
// lib/child.js
function 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);
}

Summary

    net 모듈이 프로세스에 수행할 작업을 Worker 프로세스가 수행한 작업으로 살펴보겠습니다. 워커인지 마스터인지 판단합니다. 워커라면 net.Server 인스턴스의 Listen 메서드를 해킹합니다.
  1. 워커가 호출한 Listen 메서드가 해킹되어 직접 0을 반환하지만 연결 이벤트가 발생합니다. master에 등록됨
  2. 클라이언트 연결 이벤트를 받은 후 마스터는 연결에서 클라이언트 핸들을 폴링하여 작업자에게 보냅니다.
  3. 워커는 마스터가 보낸 클라이언트 핸들을 받은 후 처리할 수 있습니다. the client request
  4. 이 글의 사례를 읽으신 후 방법을 마스터하셨다고 생각합니다. 더 흥미로운 정보를 보려면 PHP 중국어 웹사이트의 다른 관련 글을 주목해 보세요!

추천 자료:

Vue.js 양방향 바인딩 프로젝트 실제 분석


jquery가 요소 콘텐츠가 비어 있는지 확인하는 방법

위 내용은 Node.Js에서 포트 재사용 기능을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지Apr 14, 2025 am 12:05 AM

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

JavaScript 엔진 : 구현 비교JavaScript 엔진 : 구현 비교Apr 13, 2025 am 12:05 AM

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

브라우저 너머 : 실제 세계의 JavaScript브라우저 너머 : 실제 세계의 JavaScriptApr 12, 2025 am 12:06 AM

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축Apr 11, 2025 am 08:23 AM

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법Apr 11, 2025 am 08:22 AM

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

JavaScript : 웹 언어의 다양성 탐색JavaScript : 웹 언어의 다양성 탐색Apr 11, 2025 am 12:01 AM

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

JavaScript의 진화 : 현재 동향과 미래 전망JavaScript의 진화 : 현재 동향과 미래 전망Apr 10, 2025 am 09:33 AM

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

Demystifying JavaScript : 그것이하는 일과 중요한 이유Demystifying JavaScript : 그것이하는 일과 중요한 이유Apr 09, 2025 am 12:07 AM

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음