간단한 파이프라인이 있습니다.
node foo.js | node bar.js
bar.js
데이터를 얻기 위해 stdin에서 읽어옵니다 foo.js
.
하지만 내가 하고 싶은 것은 foo.js가 종료할 수 있다고 결정하기 전에 bar.js
마지막 메시지를 받는지 확인하는 것입니다. foo.js
기본적으로 간단한 요청/응답 패턴을 만들고 싶습니다.
foo는 stdout에 씁니다 --> bar는 stdin에서 읽습니다 --> bar foo에 메시지를 다시 보내는 방법은 무엇입니까?
파이프라인에서 역방향으로 통신하는 방법이 있습니까, 아니면 이것이 필요한가요?
답변1
파이프가 양방향인 시스템(NetBSD, FreeBSD, SVR4 파생 Unices(최소한 STREAMS 파이프가 있는 모든 시스템), Linux는 아님):
node foo.js <&1 | node bar.js >&0
이미 언급한 명명된 파이프 외에도 소켓 쌍을 사용할 수도 있습니다.
perl -MSocket -e '
socketpair(A, B, AF_UNIX, SOCK_STREAM, PF_UNSPEC);
if (fork) {
open STDIN, "<&A";
open STDOUT, ">&B";
exec "node", "foo.js";
} else {
open STDIN, "<&B";
open STDOUT, ">&A";
exec "node", "bar.js";
}'
또는 이름이 지정되지 않은 두 개의 파이프(예:ㅏcoproc
.
그리고 zsh
:
coproc node foo.js
node bar.js <&p >&p
ksh
:
node foo.js |&
node bar.js <&p >&p
bash
4+:
coproc node foo.js
node bar.js <&"${COPROC[0]}" >&"${COPROC[1]}"
또는 yash
의 x>>|y
파이프 연산자를 사용하십시오:
{ node foo.js <&3 3<&- | node bar.js 3<&-; } >>|3
답변2
아니요. 파이프는 단방향 통신 채널입니다. 이것이 바로 "파이프라인"이라고 불리는 이유입니다. 아무리 시도해도 석유를 파이프라인으로 다시 가져올 수 없습니다.
그러나 bar.js가 foo.js와도 통신해야 하는 경우 몇 가지 옵션이 있습니다.
- 파이프 대신 Unix 도메인 소켓을 생성하고 둘 다 별도로 시작합니다
foo.js
(bar.js
즉, 더 이상 foo.js의 출력을 bar.js로 파이프하지 않습니다). 노드에서 이 작업을 수행하는 방법을 모르지만 기본적으로 Unix 도메인 소켓은 IP 주소 대신 파일 이름을 사용하고 커널 내부에서 작동하는 네트워크 소켓입니다. 소켓은 양방향 통신에 사용되지만 단순한 파이프보다 더 많은 설정이 필요합니다(예를 들어 청취 소켓은 bar.js의 여러 인스턴스와 통신할 수 있습니다). 파일 시스템에서 Unix 도메인 소켓을 찾을 수 있지만 꼭 필요한 것은 아닙니다(사실 Linux에서는 파일 시스템에 흔적을 남기지 않고 Unix 도메인 소켓 생성을 허용합니다). - 명명된 파이프를 생성하기 위한 것입니다
mkfifo
(또는 명명된 파이프가 있는 경우 일부 노드 API를 사용하여 명명된 파이프를 생성합니다. 다시 말하지만 노드에 대해서는 모릅니다). 그런 다음 에서foo.js
명명된 파이프를 열고 읽습니다. 귀하의bar.js
스크립트는 동일한 명명된 파이프를 열고 여기에 쓸 수 있습니다.
후자는 여전히 파일 I/O를 사용하고 있기 때문에 전환하기 가장 쉽지만(명명된 파이프를 열려면 파일 시스템에서 파일을 열어야 함) 여전히 단방향입니다(각 방향에 하나씩 두 개의 채널이 있음에도 불구하고). . 전자는 약간 더 깔끔하며 필요한 경우 두 스크립트 중 하나를 다른 호스트로 더 쉽게 마이그레이션할 수 있습니다.
어쨌든 스크립트가 이제 양방향으로 통신하는 경우 명확성을 위해 한 프로세스를 파이프를 통해 다른 프로세스에 연결하는 대신 별도의 프로세스로 시작하는 것이 좋습니다. IMHO, 그들은 이제 동등한 파트너이며 명령줄에 이를 표시해야 합니다. 그러나 이는 단지 세부 사항일 뿐이며 기술적으로 반드시 필요한 것은 아닙니다.
답변3
역방향으로 의사소통하는 것은 매우 쉽지만 권장되지는 않습니다. 물론 잘못된 종류의 의사소통을 사용하면 복잡한 시스템에서 매우 좋거나 불쾌한 피드백 루프를 얻을 수 있습니다.
*nix에서는 다음과 같이 Node.js를 사용하여 이 작업을 수행할 수 있습니다.
// foo.js
process.stdout.write(process.pid);
// bar.js
process.stdin.resume().once('data', function(pid){
const writable = fs.createWriteStream(`/proc/${pid}/fd/0`);
writable.write('whatevs'); // write to stdin of foo.js
});
위의 내용은 단순화되었지만 아이디어를 얻을 수 있습니다. 이상적으로는 JSON을 사용하여 stdio 메시지를 인코딩하는 것입니다. 이를 수행하는 좋은 라이브러리는 다음과 같습니다.https://github.com/ORESoftware/json-stdio
그러나 문제는 MacOS에서는 다음을 사용할 수 없다는 것입니다 /proc/<pid>
... 지난번에 확인했을 때 이를 수행하는 유일한 좋은 방법은 이 상황에 맞는 mkfifo
고유한 도메인을 만들 fifo
거나 TCP 또는 Unix 도메인을 사용하는 것입니다. 소켓.