Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 按照创建stdout和stderr的相同顺序,从ssh命令中记录stdout和stderr_Java_Ssh_Jsch - Fatal编程技术网

Java 按照创建stdout和stderr的相同顺序,从ssh命令中记录stdout和stderr

Java 按照创建stdout和stderr的相同顺序,从ssh命令中记录stdout和stderr,java,ssh,jsch,Java,Ssh,Jsch,短版本:是否可以在通过ssh远程执行的命令的本地端记录stdout和stderr,其顺序与在远程主机上输出的顺序相同?如果是,怎么做 长版本: 我试图以与远程命令输出相同的顺序记录远程执行SSH命令(使用Jsch)的标准和错误输出。换句话说,如果远程命令将“a”写入stdout,然后将“b”写入stderr,然后将“c”写入stdout,那么我希望客户端(本地)的日志读取: a b c 以下是我到目前为止的情况。它与我想要的比较接近,但我认为它显然不能保证客户端的正确输出顺序 public in

短版本:是否可以在通过ssh远程执行的命令的本地端记录stdout和stderr,其顺序与在远程主机上输出的顺序相同?如果是,怎么做

长版本:

我试图以与远程命令输出相同的顺序记录远程执行SSH命令(使用Jsch)的标准和错误输出。换句话说,如果远程命令将“a”写入stdout,然后将“b”写入stderr,然后将“c”写入stdout,那么我希望客户端(本地)的日志读取:

a
b
c

以下是我到目前为止的情况。它与我想要的比较接近,但我认为它显然不能保证客户端的正确输出顺序

public int exec(String strCommand) throws ExceptionUnableToExecCommand {
    JSch jsch = new JSch();
    Session session = null;
    ChannelExec channel = null;
    try {
          session = jsch.getSession(user, host, 22);
          UserInfo ui = new cyclOps.jsch.UserInfo(password);
          session.setUserInfo(ui);
          session.connect();
          channel = (ChannelExec) session.openChannel("exec");
          channel.setCommand(strCommand);
          channel.setInputStream(null);
          InputStream in = channel.getInputStream();
          InputStream err = channel.getErrStream();
          channel.connect();
          /* getOutput() defined below. */
          return this.getOutput(channel, in, err);
    } catch (JSchException | IOException e) {
        throw new ExceptionUnableToExecCommand("Unable to execute " + strCommand + " " + this.toString(), e);
    } finally {
        if (channel != null) channel.disconnect();
        if (session != null) session.disconnect();
    }
}

private int getOutput(ChannelExec channel, InputStream in, InputStream err) throws IOException { 
    byte[] tmp = new byte[1024];
    while(true){
        while(in.available() > 0){
            int i=in.read(tmp, 0, 1024);
            if(i<0)break;
            this.sshLogger.logOutputFromSSH(new String(tmp, 0, i));
        }
        while(err.available() > 0){
            int i=err.read(tmp, 0, 1024);
            if(i<0)break;
            this.sshLogger.logOutputFromSSH(new String(tmp, 0, i));
        }
        if(channel.isClosed()){
            return channel.getExitStatus();
        }
        try{Thread.sleep(1000);}catch(Exception ee){}
    }
}
public int exec(字符串strCommand)抛出ExceptionUnableToExecCommand{
JSch JSch=新的JSch();
会话=空;
ChannelExec channel=null;
试一试{
session=jsch.getSession(用户,主机,22);
UserInfo ui=new cyclOps.jsch.UserInfo(密码);
session.setUserInfo(ui);
session.connect();
channel=(ChannelExec)session.openChannel(“exec”);
通道设置命令(strCommand);
channel.setInputStream(空);
InputStream in=channel.getInputStream();
InputStream err=channel.getErrStream();
channel.connect();
/*下面定义了getOutput()*/
返回此.getOutput(通道、输入、错误);
}捕获(JSCHEException | IOException e){
抛出新的ExceptionUnableToExecCommand(“无法执行”+strCommand+“”+this.toString(),e);
}最后{
如果(channel!=null)channel.disconnect();
如果(session!=null)session.disconnect();
}
}
私有int getOutput(ChannelExec通道、InputStream in、InputStream错误)引发IOException{
字节[]tmp=新字节[1024];
while(true){
while(in.available()>0){
inti=in.read(tmp,0,1024);
如果(i 0){
int i=错误读取(tmp,0,1024);

如果(i您使用的是单独的流,那么不,您无法保证获得完全相同的输出

也就是说,您的代码存在许多潜在问题,其中包括:

  • InputStream.available通常是无用的方法,应该避免使用
  • 您正在读取字节并将任意字节数组转换为字符/字符串,这可能会导致输出中断(如果您获得多字节字符,则可能最终会将其拆分)
  • 使用单个线程读取2个不同的阻塞流可能会导致死锁

    • 下面这段代码怎么样

      channel.setCommand(command);
      
      PipedOutputStream pos=new PipedOutputStream();
      PipedInputStream pis=new PipedInputStream(pos);
      channel.setOutputStream(pos);
      channel.setExtOutputStream(pos);
      InputStream in=pis;
      
      channel.connect();
      

      第三点的最佳方法是什么?两个StreamGobbler,一个用于stdout,一个用于stderr?抱歉,必须恢复“正确答案”状态。您的指导很有价值,但ymnk的答案实际上似乎以正确的顺序给了我输出。