有一个设备正在运行一些专用的、未记录的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多个这样的设备,会话没有命名约定。
还有什么我可以试试的吗?
1条答案
按热度按时间o7jaxewo1#
我认为您不了解putty连接共享功能的目的和工作原理。它帮不了你。它的行为和你的一模一样
plink.exe -ssh user@host -pw password help
命令。看起来您的实际问题是设备的ssh“exec”通道实际上不起作用。
你必须使用“shell”频道。
为此目的:
当然,那是为了测试。如果你要调用
plink
在java中,可以使用本机java特性提供命令。如果您确实需要的话,这甚至允许您延迟命令输入。尽管使用plink和普通批处理文件也是可能的(至少对于测试而言)。请参阅wait between sending login and commands to serial port using plink(这是用于串行端口连接的,但同样也适用于ssh)。对于测试,请在windows批处理文件中尝试以下操作:请注意,通常不建议使用“shell”通道。但对于许多ssh服务器有限的“设备”,它通常是唯一可行的解决方案。
实际上,这可能正是您最初使用jsch失败的原因。所以,如果你使用“shell”频道,也许你真的可以使用jsch。另请参见jsch中“shell”通道和“exec”通道之间的区别。