Nodejs 프로 세 스 간 통신

55228 단어
장면
Node 는 단일 스 레 드 에서 실행 되 지만 다 중 핵 / 다 중 컴퓨터 에서 다 중 프로 세 스 의 장점 을 이용 할 수 없다 는 것 은 아 닙 니 다.
사실 Node 는 처음에 디자인 에서 분포 식 네트워크 장면 을 고려 했다.
Node is a single-threaded, single-process system which enforces shared-nothing design with OS process boundaries. It has rather good libraries for networking. I believe this to be a basis for designing very large distributed programs. The “nodes” need to be organized: given a communication protocol, told how to connect to each other. In the next couple months we are working on libraries for Node that allow these networks.
P. S. Node 가 Node 라 는 이유 에 대해 서 만 나 보 세 요. Why is Node.js named Node.js?
2. 프로 세 스 만 들 기
통신 방식 은 프로 세 스 생 성 방식 과 관련 이 있 으 며, Node 는 프로 세 스 를 만 드 는 4 가지 방식 이 있 습 니 다.  spawn()  ,  exec()  ,  execFile()  와  fork()
spawn
const { spawn } = require('child_process'); const child = spawn('pwd'); //        // const child = spawn('find', ['.', '-type', 'f']);
spawn()  돌아 가기  ChildProcess  실례,  ChildProcess  역시 이벤트 메커니즘 (EventEmitter API) 을 바탕 으로 일부 이 벤트 를 제공 했다.
  • exit : 하위 프로 세 스 가 종료 되 었 을 때 터치 하면 프로 세 스 가 종료 되 었 음 을 알 수 있 습 니 다 (  code  와  signal 
  • disconnect : 부모 프로 세 스 호출  child.disconnect()  시 촉발
  • error : 하위 프로 세 스 생 성 에 실 패 했 거나,  kill  시 촉발
  • close : 하위 프로 세 스 의  stdio  흐름 (표준 입 출력 흐름) 종료 시 터치
  • message : 하위 프로 세 스 통과  process.send()  메 시 지 를 보 낼 때 터치 합 니 다. 부자 프로 세 스 간 에 이 를 통 해 내 장 된 메시지 메커니즘 통신
  • 통과 가능  child.stdin  ,  child.stdout  와  child.stderr  하위 프로 세 스에 접근 하 는  stdio  흐름, 이 흐름 이 닫 혔 을 때 하위 프로 세 스 가 실 행 됩 니 다.  close  사건
    P.S.  close  과  exit  의 차 이 는 주로 다 중 프로 세 스 가 같은 것 을 공유 하 는 데 나타난다.  stdio  흐 르 는 장면 에서 어떤 프로 세 스 가 종료 되 었 다 는 것 은 의미 하지 않 습 니 다.  stdio  흐름 이 닫 혔 습 니 다.
    하위 프로 세 스 중,  stdout/stderr  읽 기 가능 한 특성 을 가지 고 있 으 며,  stdin  Writable 특성 을 가지 고 있 습 니 다. 주 프로 세 스 의 상황 과 정반 대 입 니 다. :
    child.stdout.on('data', (data) => { console.log(`child stdout:
    ${data}`); }); child.stderr.on('data', (data) => { console.error(`child stderr:
    ${data}`); });

    프로 세 스 이용  stdio  흐름 의 파이프 특성 은 더욱 복잡 한 일 을 완성 할 수 있다. 예 를 들 어:
    const { spawn } = require('child_process'); const find = spawn('find', ['.', '-type', 'f']); const wc = spawn('wc', ['-l']); find.stdout.pipe(wc.stdin); wc.stdout.on('data', (data) => { console.log(`Number of files ${data}`); });

    작용  find . -type f | wc - 현재 디 렉 터 리 파일 의 수량 을 재 귀적 으로 통계 합 니 다.
    IPC 옵션
    그리고  spawn()  방법의  stdio  옵션 을 사용 하면 IPC 체 제 를 구축 할 수 있 습 니 다.
    const { spawn } = require('child_process'); const child = spawn('node', ['./ipc-child.js'], { stdio: [null, null, null, 'ipc'] }); child.on('message', (m) => { console.log(m); }); child.send('Here Here'); // ./ipc-child.js process.on('message', (m) => { process.send(`< ${m}`); process.send('>     x3'); });

    ... 에 대하 여  spawn()  IPC 옵션 에 대한 자세 한 정 보 는 보 세 요. options.stdio
    exec spawn()  방법 은 기본적으로 셸 을 만 들 지 않 고 들 어 오 는 명령 을 수행 합 니 다 (그래서) 성능 이 좀 좋아요. ),그리고  exec()  방법 은 셸 을 만 듭 니 다. 또한,  exec()  stream 기반 이 아니 라 명령 에 들 어 온 실행 결 과 를 buffer 에 잠시 저장 하고 전체 반전 함수 에 전달 합 니 다.exec()  방법의 특징 은 셸 문법 완전 지원 ,임의의 셸 스 크 립 트 를 직접 전송 할 수 있 습 니 다. 예 를 들 어:
    const { exec } = require('child_process'); exec('find . -type f | wc -l', (err, stdout, stderr) => { if (err) { console.error(`exec error: ${err}`); return; } console.log(`Number of files ${stdout}`); });

    그러나.  exec()  방법 도 이 로 인해 존재 한다. 명령 주입 의 안전 위험 은 사용자 입력 등 동적 내용 을 포함 하 는 장면 에서 특히 주의해 야 한다. 따라서  exec()  방법의 적용 장면 은 셸 문법 을 직접 사용 하고 예상 출력 데 이 터 량 이 많 지 않 기 를 바 랍 니 다 (메모리 압력 이 존재 하지 않 습 니 다).
    그렇다면 셸 문법 도 지원 하고 stream IO 장점 도 가 진 방식 이 있 습 니까?
    있다 쌍방 이 모두 좋게 하 는 방식 다음 과 같다.
    const { spawn } = require('child_process'); const child = spawn('find . -type f | wc -l', { shell: true }); child.stdout.pipe(process.stdout);

    열다  spawn()  의  shell  옵션 을 선택 하고 통과  pipe()  명령 실행 결 과 를 볼 수 있 도록 하위 프로 세 스 의 표준 출력 을 현재 프로 세 스 의 표준 입력 에 간단하게 받 습 니 다. 실제로 더 쉬 운 방법 이 있 습 니 다.
    const { spawn } = require('child_process'); process.stdout.on('data', (data) => { console.log(data); }); const child = spawn('find . -type f | wc -l', { shell: true, stdio: 'inherit' });
    stdio: 'inherit'  하위 프로 세 스 가 현재 프로 세 스 의 표준 입 출력 을 계승 할 수 있 도록 합 니 다 (공유)  stdin  ,  stdout  와  stderr  따라서 상례 로 현재 프로 세 스 를 감청 할 수 있 습 니 다.  process.stdout  의  data  이벤트 가 하위 프로 세 스 의 출력 결 과 를 가 져 옵 니 다.
    이외에  stdio  와  shell  옵션,  spawn()  다음 과 같은 다른 옵션 도 지원 합 니 다.
    const child = spawn('find . -type f | wc -l', { stdio: 'inherit', shell: true, //       ,  process.env env: { HOME: '/tmp/xxx' }, //          cwd: '/tmp', //          detached: true });

    주의 하 다. ,  env  옵션 은 환경 변수 형식 으로 하위 프로 세 스에 데 이 터 를 전달 하 는 것 외 에 샌 드 박스 식 환경 변수 격 리 를 실현 할 수 있 습 니 다. 기본 값 으로  process.env  하위 프로 세 스 의 환경 변수 집합 으로 하위 프로 세 스 는 현재 프로 세 스 와 마찬가지 로 모든 환경 변 수 를 방문 할 수 있 습 니 다. 상기 에서 사용자 정의 대상 을 하위 프로 세 스 의 환경 변수 집합 으로 지정 하면 하위 프로 세 스 는 다른 환경 변 수 를 방문 할 수 없습니다.
    따라서 환경 변 수 를 증가 / 삭제 하려 면 이렇게 해 야 합 니 다.
    var spawn_env = JSON.parse(JSON.stringify(process.env)); // remove those env vars delete spawn_env.ATOM_SHELL_INTERNAL_RUN_AS_NODE; delete spawn_env.ELECTRON_RUN_AS_NODE; var sp = spawn(command, ['.'], {cwd: cwd, env: spawn_env});
    detached  옵션 이 더 재 미 있 습 니 다.
    const { spawn } = require('child_process'); const child = spawn('node', ['stuff.js'], { detached: true, stdio: 'ignore' }); child.unref();

    이러한 방식 으로 만 든 독립 프로 세 스 행 위 는 운영 체제 에 달 려 있 습 니 다. Windows 에서 detached 하위 프로 세 스 는 자신의 console 창 을 가지 고 있 으 며 Linux 에 서 는 이 프로 세 스 가 새 프로 세 스 그룹 만 들 기 (이 기능 은 하위 프로 세 스 족 을 관리 하 는 데 사용 할 수 있 습 니 다. tree-kill 매 직unref()  방법 은 관 계 를 끊 는 데 사 용 됩 니 다. "부모" 프로 세 스 는 독립 적 으로 종료 할 수 있 습 니 다. (하위 프로 세 스 가 따라 종료 되 지 않 습 니 다) 그러나 이 때 하위 프로 세 스 를 주의해 야 합 니 다.  stdio  '부모' 프로 세 스 에 독립 해 야 합 니 다. 그렇지 않 으 면 '부모' 프로 세 스 가 종 료 된 후에 도 하위 프로 세 스 가 영향 을 받 을 수 있 습 니 다.
    execFile
    const { execFile } = require('child_process'); const child = execFile('node', ['--version'], (error, stdout, stderr) => { if (error) { throw error; } console.log(stdout); });

    ... 과  exec()  방법 은 유사 하지만 셸 을 통 해 실행 되 지 않 습 니 다 (그래서 성능 이 조금 좋 습 니 다). 그래서 전송 을 요구 합 니 다. 실행 파일 。Windows 의 일부 파일 은 직접 실행 할 수 없습니다. 예 를 들 어  .bat  와  .cmd  이 서류 들 은 사용 할 수 없습니다.  execFile()  집행 은 빌 릴 수 밖 에 없다.  exec()  또는 오픈  shell  옵션 의  spawn()
    P. S. 와  exec()  똑 같 아 요. stream 기반 이 아 닙 니 다. ,출력 데이터 양 위험 도 존재 합 니 다.
    xxxSync spawn  ,  exec  와  execFile  하위 프로 세 스 가 종 료 될 때 까지 대응 하 는 동기 화 차단 버 전이 있 습 니 다.
    const { 
      spawnSync, execSync, execFileSync, } = require('child_process');

    동기 화 방법 은 스 크 립 트 작업 을 간소화 하 는 데 사 용 됩 니 다. 예 를 들 어 시작 프로 세 스, 다른 때 는 이러한 방법 을 피해 야 합 니 다.
    fork fork()  네.  spawn()  의 변 체 는 Node 프로 세 스 를 만 드 는 데 사 용 됩 니 다. 가장 큰 특징 은 부자 프로 세 스 자체 통신 체제 (IPC 파이프) 입 니 다.
    The child_process.fork() method is a special case of child_process.spawn() used specifically to spawn new Node.js processes. Like child_process.spawn(), a ChildProcess object is returned. The returned ChildProcess will have an additional communication channel built-in that allows messages to be passed back and forth between the parent and child. See subprocess.send() for details.
    예 를 들 면:
    var n = child_process.fork('./child.js'); n.on('message', function(m) { console.log('PARENT got message:', m); }); n.send({ hello: 'world' }); // ./child.js process.on('message', function(m) { console.log('CHILD got message:', m); }); process.send({ foo: 'bar' });

    ... 때문에  fork()  자체 통신 체제 의 장점 은 특히 시간 소모 논 리 를 분리 하 는 데 적합 하 다. 예 를 들 어:
    const http = require('http'); const longComputation = () => { let sum = 0; for (let i = 0; i < 1e9; i++) { sum += i; }; return sum; }; const server = http.createServer(); server.on('request', (req, res) => { if (req.url === '/compute') { const sum = longComputation(); return res.end(`Sum is ${sum}`); } else { res.end('Ok') } }); server.listen(3000);

    이렇게 하 는 치 명 적 인 문 제 는 누군가가 방문 하면  /compute  후속 요청 은 제때에 처리 할 수 없습니다. 이벤트 순환 이 아직  longComputation  시간 계산 이 끝 날 때 까지 막 혀 있어 야 서비스 능력 을 회복 할 수 있다.
    주 프로 세 스 의 이벤트 순환 을 막 는 데 시간 이 걸 리 지 않도록  longComputation()  하위 프로 세 스 로 나 누 기:
    // compute.js
    const longComputation = () => { let sum = 0; for (let i = 0; i < 1e9; i++) { sum += i; }; return sum; }; //   ,         process.on('message', (msg) => { const sum = longComputation(); process.send(sum); });

    주 프로 세 스 하위 프로 세 스 실행 열기  longComputation 
    const http = require('http'); const { fork } = require('child_process'); const server = http.createServer(); server.on('request', (req, res) => { if (req.url === '/compute') { const compute = fork('compute.js'); compute.send('start'); compute.on('message', sum => { res.end(`Sum is ${sum}`); }); } else { res.end('Ok') } }); server.listen(3000);

    주 프로 세 스 의 이벤트 순환 은 더 이상 시간 계산 에 의 해 막 히 지 않 지만 프로 세 스 의 수량 은 더 제한 되 어야 합 니 다. 그렇지 않 으 면 자원 이 프로 세 스 에 의 해 소 모 될 때 서비스 능력 이 영향 을 받 을 수 있 습 니 다.
    P. S. 실제로,  cluster  모듈 은 다 중 프로 세 스 서비스 능력 에 대한 패키지 입 니 다. 사고방식 은 이 간단 한 예시 와 유사 하 다
    통신 방식
    1. stdin / stdout 을 통 해 json 전달
    stdin/stdout and a JSON payload
    가장 직접적인 통신 방식 으로 하위 프로 세 스 의 handle 를 가 져 오 면 접근 할 수 있 습 니 다.  stdio  흐름  message  형식 으로 즐 거 운 통신 을 시작 합 니 다.
    const { spawn } = require('child_process'); child = spawn('node', ['./stdio-child.js']); child.stdout.setEncoding('utf8'); //    -  child.stdin.write(JSON.stringify({ type: 'handshake', payload: '   ' })); //    -  child.stdout.on('data', function (chunk) { let data = chunk.toString(); let message = JSON.parse(data); console.log(`${message.type} ${message.payload}`); });

    하위 프로 세 스 와 유사:
    // ./stdio-child.js
    //    - 
    process.stdin.on('data', (chunk) => { let data = chunk.toString(); let message = JSON.parse(data); switch (message.type) { case 'handshake': //    -  process.stdout.write(JSON.stringify({ type: 'message', payload: message.payload + ' : hoho' })); break; default: break; } });

    P. S. VS 코드 프로 세 스 간 통신 은 이런 방식 을 채택 했다. 구체 적 으로 보면 access electron API from vscode extension
    뚜렷 하 다 제한 하 다. '하위' 프로 세 스 를 가 져 와 야 하 는 handle 입 니 다. 두 개의 완전히 독립 된 프로 세 스 간 에 이런 방식 으로 통신 할 수 없습니다 (예 를 들 어 크로스 응용, 심지어 기 계 를 뛰 어 넘 는 장면)
    P. S. stream 및 pipe 에 대한 자세 한 정 보 는 보 세 요. Node 의 흐름
    2. 원생 IPC 지원
    ... 와 같다  spawn()  및  fork()  의 예 를 들 어 프로 세 스 간 에 내 장 된 IPC 메커니즘 을 통 해 통신 할 수 있다.
    부모 프로 세 스:
  • process.on('message')  받 음
  • child.send() 
  • 하위 프로 세 스:
  • process.on('message')  받 음
  • process.send() 
  • 제한 동상, 마찬가지 로 한 쪽 이 다른 쪽 의 handle 를 받 을 수 있어 야 합 니 다.
    3.sockets
    네트워크 를 통 해 프로 세 스 간 통신 을 완성 합 니 다. 프로 세 스 를 뛰 어 넘 을 수 있 을 뿐만 아니 라 기계 도 뛰 어 넘 을 수 있다.
    node-ipc 이런 방안 을 채택 하 다. 예 를 들 면:
    // server
    const ipc=require('../../../node-ipc'); ipc.config.id = 'world'; ipc.config.retry= 1500; ipc.config.maxConnections=1; ipc.serveNet( function(){ ipc.server.on( 'message', function(data,socket){ ipc.log('got a message : ', data); ipc.server.emit( socket, 'message', data+' world!' ); } ); ipc.server.on( 'socket.disconnected', function(data,socket){ console.log('DISCONNECTED

    ',arguments); } ); } ); ipc.server.on( 'error', function(err){ ipc.log('Got an ERROR!',err); } ); ipc.server.start(); // client const ipc=require('node-ipc'); ipc.config.id = 'hello'; ipc.config.retry= 1500; ipc.connectToNet( 'world', function(){ ipc.of.world.on( 'connect', function(){ ipc.log('## connected to world ##', ipc.config.delay); ipc.of.world.emit( 'message', 'hello' ); } ); ipc.of.world.on( 'disconnect'

    좋은 웹페이지 즐겨찾기