使用plink-shareexists将命令发送到先前与java建立的连接

093gszye  于 2021-07-07  发布在  Java
关注(0)|答案(1)|浏览(325)

有一个设备正在运行一些专用的、未记录的ssh守护程序,我需要为其编写ssh客户端,它可以从文件发送和执行命令。jsch不适合这个项目,所以我们选择了plink。
问题是,连接到设备后,提示被设备的操作系统“暂停”,只有在2-3秒后,当一些欢迎消息和一些警报被收集并显示时才会释放。但当这种情况发生时,plink已经发布了会话。
命令本身并不特别: plink.exe -ssh user@host -pw password help 当我在标准的linux服务器上执行它时,它可以完美地工作。但是,当连接建立时,提示还没有准备好,所以这个设备会“吞下”这个命令。
据我所知,plink是一种一次性的东西,这意味着它将发出命令,等待响应,然后终止连接-但它有一个-shareexists参数,该参数应该搜索到同一主机的现有连接,并使用该参数发送命令。
使用这个,我尝试创建一个多线程方法,首先创建登录线程,当它处于活动状态时,命令执行线程应该通过-shareexists钩住它。
如果我理解正确,应该这样使用: plink.exe -shareexists -ssh user@host -pw password help 结果是成功的一半,因为我可以看到登录线程是成功的,并且在命令执行开始时应该是活动的:

SSHConnectionHandler.main: starting ssh test
PLinkLoginThread.PLinkLoginThread: plink login thread created
PLinkLoginThread.PLinkLoginThread: Thread[Thread-0,5,main]
PLinkLoginThread.doLogin: starting login procedure
PLinkLoginThread.doLogin: plink.exe -ssh user@host -pw password
PLinkLoginThread.doLogin: login procedure finished
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-55-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

  System information as of Tue Dec  1 14:42:43 CET 2020

  System load:  0.01                Processes:           201
  Usage of /:   49.1% of 113.81GB   Users logged in:     1
  Memory usage: 36%                 IP address for eth0: x.x.x.x
  Swap usage:   2%

  => /mnt/backup/dkcad2 is using 88.4% of 98.30GB

  Graph this data and manage this system at:
    https://landscape.canonical.com/

301 packages can be updated.
231 updates are security updates.

Last login: Tue Dec  1 14:16:52 2020 from y.y.y.y
$ 
PLink Thread is alive: true
SSHConnectionHandler.main: executing command while login thread is alive
SSHConnectionHandler.main: pLinkLoginThread is alive: true
SSHConnectionHandler.main: sehr gut, sehr gut
PLinkCommandExecutorThread.pLinkCommandExecutorThread: plink executor thread created
PLinkCommandExecutorThread.pLinkCommandExecutorThread: Thread[Thread-1,5,main]
PLinkCommandExecutorThread.run: executing command
plink.exe -shareexists -ssh user@host -pw password help
PLinkCommandExecutorThread.run: command executed

但是由于某些原因,要么命令没有发送到登录线程会话,要么响应被吞没。
以下是线程执行的代码:

public static void main(String[] args) {

        String sshStream = null;
        String command = "ls";

        System.out.println("SSHConnectionHandler.main: starting ssh test");
        pLinkLoginThread = new PLinkLoginThread(testHost, 22, testUser, testPassword);
        try {
            pLinkLoginThread.start();
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            while (pLinkLoginThread.isAlive()) {
                System.out.println("SSHConnectionHandler.main: executing command while login thread is alive");
                System.out.println("SSHConnectionHandler.main: pLinkLoginThread is alive: " + pLinkLoginThread.isAlive());
                if (pLinkLoginThread.isAlive()) {
                    System.out.println("SSHConnectionHandler.main: sehr gut, sehr gut");
                    pLinkCommandExecutorThread = new PLinkCommandExecutorThread(command, testHost, 22, testUser, testPassword);
                    pLinkCommandExecutorThread.start();
                    pLinkCommandExecutorThread.join();
                } else {
                    System.out.println("SSHConnectionHandler.main: das ist kein Kakao, Günther!");
                }
            }
        } catch (Exception e) {
            System.out.println("SSHConnectionHandler.main: exception during command execution");
            e.printStackTrace();
        }
    }

以下是两条线索:
登录线程

public class PLinkLoginThread extends Thread {

    PLinkLoginThread(String host, int port, String user, String password) {

        System.out.println("PLinkLoginThread.PLinkLoginThread: plink login thread created");
        System.out.println("PLinkLoginThread.PLinkLoginThread: " + this);
        run(host, port, user, password);
    }

    public void run(String host, int port, String user, String password) {

        Process process;
        String login = "plink.exe -ssh " + user + "@" + host + " -pw " + password;

        try {
            Runtime r = Runtime.getRuntime();
            System.out.println("PLinkLoginThread.doLogin: starting login procedure");
            System.out.println("PLinkLoginThread.doLogin: " + login);
            process = r.exec(login);
            process.waitFor(3, TimeUnit.SECONDS);
            System.out.println("PLinkLoginThread.doLogin: login procedure finished");
            System.out.println(SSHConnectionHandler.readInputStream(process.getInputStream()));
            System.out.println("PLink Thread is alive: " + process.isAlive());
        } catch (Exception e) {
            System.out.println("PLinkLoginThread.doLogin");
            e.printStackTrace();
        }

    }
}

命令执行线程(应该挂接到已打开的连接中):

public class PLinkCommandExecutorThread extends Thread {

    PLinkCommandExecutorThread (String command, String host, int port, String user, String password) {

        System.out.println("PLinkCommandExecutorThread.pLinkCommandExecutorThread: plink executor thread created");
        System.out.println("PLinkCommandExecutorThread.pLinkCommandExecutorThread: " + this);
        run(command, user, host, password);
    }

    public void run(String command, String user, String host, String password) {

        Process process;
        String commandToExecute = "plink.exe -shareexists -ssh " + user + "@" + host + " -pw " + password + command;

        try {
            Runtime r = Runtime.getRuntime();
            System.out.println("PLinkCommandExecutorThread.run: executing command");
            System.out.println(commandToExecute);
            process = r.exec(commandToExecute);
            process.waitFor(3, TimeUnit.SECONDS);
            System.out.println("PLinkCommandExecutorThread.run: command executed");
            System.out.println(SSHConnectionHandler.readInputStream(process.getInputStream()));
            System.out.println(SSHConnectionHandler.readInputStream(process.getErrorStream()));
        } catch (Exception e) {
            System.out.println("PLinkCommandExecutorThread.run");
            e.printStackTrace();
        }
    }
}

使用保存的putty会话也不是一个选项,因为有300多个这样的设备,会话没有命名约定。
还有什么我可以试试的吗?

o7jaxewo

o7jaxewo1#

我认为您不了解putty连接共享功能的目的和工作原理。它帮不了你。它的行为和你的一模一样 plink.exe -ssh user@host -pw password help 命令。
看起来您的实际问题是设备的ssh“exec”通道实际上不起作用。
你必须使用“shell”频道。
为此目的:

echo command | plink.exe -ssh user@host -pw password

当然,那是为了测试。如果你要调用 plink 在java中,可以使用本机java特性提供命令。如果您确实需要的话,这甚至允许您延迟命令输入。尽管使用plink和普通批处理文件也是可能的(至少对于测试而言)。请参阅wait between sending login and commands to serial port using plink(这是用于串行端口连接的,但同样也适用于ssh)。对于测试,请在windows批处理文件中尝试以下操作:

(
  echo command1
  timeout /t 5 > nul
  echo command2
  timeout /t 5 > nul
  echo command3
  timeout /t 5 > nul
) | plink.exe ...

请注意,通常不建议使用“shell”通道。但对于许多ssh服务器有限的“设备”,它通常是唯一可行的解决方案。
实际上,这可能正是您最初使用jsch失败的原因。所以,如果你使用“shell”频道,也许你真的可以使用jsch。另请参见jsch中“shell”通道和“exec”通道之间的区别。

相关问题