为什么javascript ssh2在使用shell时会陷入无限循环

为什么javascript ssh2在使用shell时会陷入无限循环,javascript,node.js,typescript,Javascript,Node.js,Typescript,我试图让我的应用程序通过使用ssh2npm包在另一个系统上执行sudo命令。我有最终的结果,但由于某种原因,代码被困在一个无限循环中。我不明白这是怎么可能的,因为我认为关闭与conn.end的连接可以防止这种情况发生。有谁能帮我解释一下为什么我会被困在一个无限循环中 正在执行的主代码: function sshRunSudoCommand(user, pass, lanIP, command) { return new Promise((resolve, reject) => {

我试图让我的应用程序通过使用ssh2npm包在另一个系统上执行sudo命令。我有最终的结果,但由于某种原因,代码被困在一个无限循环中。我不明白这是怎么可能的,因为我认为关闭与conn.end的连接可以防止这种情况发生。有谁能帮我解释一下为什么我会被困在一个无限循环中

正在执行的主代码:

function sshRunSudoCommand(user, pass, lanIP, command) {

  return new Promise((resolve, reject) => {
    var Connection  = require('ssh2');
    var pwSent      = false;
    var sudosu      = false;
    var password    = pass;
    var conn        = new Connection();

    conn.on('ready', function() {
      console.log('Sudo Connection :: ready');
      conn.shell( function(err, stream) {
        if (err) throw err;
        stream
          .on('close', function() {
          console.log('Sudo Stream :: close');
          conn.end();
          resolve();
        })
          .on('data', function(data) {
          //handle sudo password prompt
          stream.write(password + '\n');
          stream.write(command + '\n');
          console.log('Sudo STDOUT: ' + data);
          resolve(data);
        })
          .on('exit', function(code, signal) {
          let exitCode = 'Stream :: exit :: code: ' + code + ', signal: ' + signal;
          conn.end();
          resolve(exitCode);
        })
          .on('end', function() {
            conn.end();
            resolve('end');
          })
          .stderr.on('data', function(data) {
          console.log('STDERR: ' + data);
          conn.end();
          resolve(data);
        });

      });
    })
      .on('keyboard-interactive',
        function(name, instructions, instructionsLang, prompts, finish) {
          // Pass answers to `prompts` to `finish()`. Typically `prompts.length === 1`
          // with `prompts[0] === "Password: "`
          console.log('pass before finish is ', pass);
          finish([pass]);
        }).on('ready', function() {
    }).connect({
      host: lanIP,
      port: 22,
      username: user,
      password: pass,
      readyTimeout: 99999,
      tryKeyboard: true // this attempts keyboard-interactive auth
    });
  };
}
结果:(一次又一次地重复)


所以我发现我需要做两件事来防止重复动作

  • 我需要向stream.write添加和“exit”命令,以告诉shell结束我用conn.shell创建的会话

  • 然后,我可以将resolve()回调向下移动到代码的.on('exit)部分,以便只有在成功运行exit命令后才能返回

  • 最后的代码如下所示:

    function sshRunSudoCommand(user, pass, lanIP, command) {
    
      return new Promise((resolve, reject) => {
        var Connection  = require('ssh2');
        var password    = pass;
        var conn        = new Connection();
    
        conn.on('ready', function() {
          console.log('Sudo Connection :: ready');
          conn.shell( function(err, stream) {
            if (err) throw err;
            stream
              .on('close', function() {
              console.log('Sudo Stream :: close');
              conn.end();
              resolve();
            })
              .on('data', function(data) {
              //handle sudo password prompt
              stream.write(password + '\n');
              stream.write(command + '\n');
              stream.write('exit\n');
            })
              .on('exit', function(code, signal) {
              let exitCode = 'Stream :: exit :: code: ' + code + ', signal: ' + signal;
              conn.end();
              resolve(exitCode);
            })
              .on('end', function() {
                conn.end();
                resolve('end');
              })
              .stderr.on('data', function(data) {
              console.log('STDERR: ' + data);
              conn.end();
              resolve(data);
            });
    
          });
        })
          .on('keyboard-interactive',
            function(name, instructions, instructionsLang, prompts, finish) {
              // Pass answers to `prompts` to `finish()`. Typically `prompts.length === 1`
              // with `prompts[0] === "Password: "`
              console.log('pass before finish is ', pass);
              finish([pass]);
            }).on('ready', function() {
        }).connect({
          host: lanIP,
          port: 22,
          username: user,
          password: pass,
          readyTimeout: 99999,
          tryKeyboard: true // this attempts keyboard-interactive auth
        });
      };
    }
    

    所以我发现我需要做两件事来防止重复动作

  • 我需要向stream.write添加和“exit”命令,以告诉shell结束我用conn.shell创建的会话

  • 然后,我可以将resolve()回调向下移动到代码的.on('exit)部分,以便只有在成功运行exit命令后才能返回

  • 最后的代码如下所示:

    function sshRunSudoCommand(user, pass, lanIP, command) {
    
      return new Promise((resolve, reject) => {
        var Connection  = require('ssh2');
        var password    = pass;
        var conn        = new Connection();
    
        conn.on('ready', function() {
          console.log('Sudo Connection :: ready');
          conn.shell( function(err, stream) {
            if (err) throw err;
            stream
              .on('close', function() {
              console.log('Sudo Stream :: close');
              conn.end();
              resolve();
            })
              .on('data', function(data) {
              //handle sudo password prompt
              stream.write(password + '\n');
              stream.write(command + '\n');
              stream.write('exit\n');
            })
              .on('exit', function(code, signal) {
              let exitCode = 'Stream :: exit :: code: ' + code + ', signal: ' + signal;
              conn.end();
              resolve(exitCode);
            })
              .on('end', function() {
                conn.end();
                resolve('end');
              })
              .stderr.on('data', function(data) {
              console.log('STDERR: ' + data);
              conn.end();
              resolve(data);
            });
    
          });
        })
          .on('keyboard-interactive',
            function(name, instructions, instructionsLang, prompts, finish) {
              // Pass answers to `prompts` to `finish()`. Typically `prompts.length === 1`
              // with `prompts[0] === "Password: "`
              console.log('pass before finish is ', pass);
              finish([pass]);
            }).on('ready', function() {
        }).connect({
          host: lanIP,
          port: 22,
          username: user,
          password: pass,
          readyTimeout: 99999,
          tryKeyboard: true // this attempts keyboard-interactive auth
        });
      };
    }