我正在开发一个库/工具,让用户通过SSH执行任意命令。总的来说,这个lib /工具将作为软件部署工具,需要访问远程机器来执行几个命令(cd,mkdir,git ..., npm install ,scp等)。
虽然它基本上可以通过SSH执行远程命令,但似乎每次执行命令npm install
时,SSH连接都会终止。我无法分辨是什么导致了这种情况,但这个非常简单的Node.js
脚本可以证明它:
const spawn = require('child_process').spawn;
const bat = spawn('ssh', ['-T', '-oRequestTTY=no', '-oBatchMode=yes', 'user@host']);
bat.stdout.on('data', (data) => console.log('STDOUT: ' + data.toString()));
bat.stderr.on('data', (data) => console.log('STDERR: ' + data.toString()));
bat.on('exit', (code) => console.log(`Child exited with code ${code}`));
setTimeout(() => {
bat.stdin.write('pwd -P\n');
bat.stdin.write('cd someDir\n');
bat.stdin.write('npm install\n');
setTimeout(() => bat.stdin.write('pwd -P\n'), 2000);
}, 2000);
这将在npm install
之后中断/终止分叉的SSH进程,因此延迟的pwd -P
也将失败。删除npm install
命令将使SSH进程保持不变,直到用户终止该应用程序。
当我使用c库libssh
时遇到了这个问题,我遇到了同样的问题,尽管我没有注意到npm install
命令似乎实际上触发了问题。请参阅此相关帖子:Channel in libssh gets closed for no obvious reason
我发现的是:
1.我使用的是非pty SSH shell
2. libssh
数据包级调试输出显示服务器在连接关闭之前发送的数据包98
3.根据RFC,数据包98为SSH_MSG_CHANNEL_REQUEST
,其中 也可用于请求 pty
所以我的假设是,我正在通过SSH处理非pty shell,并且npm
程序中的某些内容直接或间接导致服务器端请求pty,这是无法处理的通过我正在处理的非pty shell,因此,SSH连接在协议级别上关闭。
现在我的问题是,是什么导致这种情况,有没有办法摆脱这个问题?
可能会在29日更新
实际上,我能够进一步调查此问题。我开始编辑npm-cli.js
并注释掉所有内容,然后逐步取消注释行,以查看将触发上述行为的内容。
起初,似乎通过npmlog
包含的集合阻止模块导致了这个问题,但是在 index.js:4 (也就是在 index.js:4 中注释了集合阻塞的实际代码之后只有stream._handle.setBlocking(blocking)
),不良行为仍然会发生,这让我感到困惑。进一步的实验表明,实际上process.stdout
的单个部分导致了整个问题。
为了验证,我做了以下事情:
if (process.stdout) ;
。这基本上什么都不做,但如果执行上述测试程序,则会导致再次发生错误。if (process.stdout) ;
更改为if (process) ;
- 测试程序现在将再次运行而不会出错。所以基本上可以改变上面描述错误的Node.js测试程序,以便调用一个简单的oneline脚本代替npm install
,这会导致同样的错误:
const spawn = require('child_process').spawn;
const bat = spawn('ssh', ['user@host']);
setTimeout(() => {
bat.stdin.write('node test.js\n'); // this breaks it
setTimeout(() => bat.stdin.write('pwd -P\n'), 2000);
}, 2000);
test.js
包含:
if (process.stdout) ; // only this line
我不知道进程全局对象是如何构造的,或者这里发生了什么,但是Node.js' process / process.stdout对象以某种方式破坏了SSH连接。因此,我认为这不是npm的实际问题,只是间接的。
有人可以帮忙解释一下吗?