【问题标题】:Pass handle down pipeline将句柄向下传递到管道
【发布时间】:2018-04-26 12:40:36
【问题描述】:

说我有

node foo.js | node bar.js

有没有办法将 foo 的标准输入上的句柄传递给 bar.js?

我有一种罕见的情况,我想在管道中进行反向通信。

至少我知道我可以发送node bar.jsnode foo.js 的pid。鉴于该 pid,在 *nix 上,我应该能够使用以下命令写入 foo 的标准输入:

/proc/<pid>/fd/0

但是有没有办法在 MacOS 上做同样的事情?

【问题讨论】:

  • 如果需要双向通信,最好使用套接字(TCP 或 Unix)。这样的解决方案可以接受吗?
  • @cdhowie 是的,那太好了,如果可能的话,x 平台更可取
  • @AlexanderMills,你有机会看看我的回答吗?

标签: node.js macos stdin pid file-descriptor


【解决方案1】:

所以有不同的方法。

方法 1 - IOCTL

灵感来源于

https://stackoverflow.com/a/36522620/2830850

所以你创建了writevt.c 包含以下内容的文件

/*
 * Mostly ripped off of console-tools' writevt.c
 */

#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>

char *progname;

static int usage() {
    printf("Usage: %s ttydev text\n", progname);
    return 2;
}

int main(int argc, char **argv) {
    int fd, argi;
    char *term = NULL;
    char *text = NULL;

    progname = argv[0];

    argi = 1;

    if (argi < argc)
        term = argv[argi++];
    else {
        fprintf(stderr, "%s: no tty specified\n", progname);
        return usage();
    }

    if (argi < argc)
        text = argv[argi++];
    else {
        fprintf(stderr, "%s: no text specified\n", progname);
        return usage();
    }

    if (argi != argc) {
        fprintf(stderr, "%s: too many arguments\n", progname);
        return usage();
    }

    fd = open(term, O_RDONLY);
    if (fd < 0) {
        perror(term);
        fprintf(stderr, "%s: could not open tty\n", progname);
        return 1;
    }

    while (*text) {
        if (ioctl(fd, TIOCSTI, text)) {
            perror("ioctl");
            return 1;
        }
        text++;
    }

    return 0;
}

使用下面编译它

gcc -o writevt writevt.c

然后将root权限添加到同一个

sudo chown root:wheel writevt
sudo chmod 4755 writevt

现在我用下面的代码创建了一个简单的foo.js

var stdin = process.openStdin();

stdin.addListener("data", function(d) {
    console.log(process.env.NAME + " entered: [" +
        d.toString().trim() + "]");
});

然后在终端中首先运行tty 命令

$ tty
/dev/ttys019

现在运行如下代码

NAME=A node foo.js  | NAME=B node foo.js

现在从另一个终端运行以下命令

./writevt /dev/ttys019 "FROM external command^M"

^M 在 Mac 上是 CTRL+V + CTRL+ENTER

gif 可以看出,输入到达 A 的 stdin,然后 A 在标准输出上打印,然后由 B 接收。所以如果我像下面这样修改代码

var stdin = process.openStdin();

stdin.addListener("data", function(d) {
    console.log(process.env.NAME + " entered: [" +
        d.toString().trim() + "]");
});

if (process.env.NAME === "B") {
    setInterval(function() {
        require('child_process').exec(`./writevt /dev/ttys019 "Hello from B?
"`)
    }, 1000)
}

注意 1^M 是在上述代码中使用 Vim 添加的

注意 2:TTY 位置已在此硬编码,但您可以通过运行将其传递给环境变量

export TTY=`tty`

然后在代码中使用process.env.TTY。更新的结果是

方法 2 - FIFO 文件

在这种方法中,您首先创建一个 fifo 文件

$ mkfifo nodebridge

现在你改变你的代码如下

var stdin = process.openStdin();
var fs = require("fs")
stdin.addListener("data", function(d) {
    console.log(process.env.NAME + " entered: [" +
        d.toString().trim() + "]");
});

if (process.env.NAME === "B") {
    setInterval( () => {
        require('child_process').exec('printf "Hello from B?\\n" > nodebridge')
    }, 1000);
}

然后像下面这样运行命令

NAME=A node foo.js < nodebridge | NAME=B node foo.js

【讨论】:

  • 很好的解释,你如何创建gif?什么节目? :)
  • @MaciejPulikowski,我从其他人那里得到了更好的选择。现在我使用getkap.co
  • 如果你使用Linux,那么一个不错的选择是github.com/phw/peek。现在不要说我用过 windows ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-17
  • 1970-01-01
  • 2012-03-16
  • 2015-07-15
  • 2019-12-19
  • 1970-01-01
  • 2013-01-11
相关资源
最近更新 更多