java通过ssh连接执行shell命令,文件传输方式
作者:kaili230
这篇文章主要介绍了java通过ssh连接执行shell命令,文件传输方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
java通过ssh连接执行shell命令,文件传输
JSch 是SSH2的纯 Java 实现 。
JSch 允许您连接到 sshd 服务器并使用端口转发、X11 转发、文件传输等,可以将其功能集成到您自己的 Java 程序中。
JSch 是在BSD 风格许可下获得许可的。
JSCH 官网:http://www.jcraft.com/jsch/
zip文件中有很多demo.
jar为依赖jar
maven 依赖
<dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>
测试代码
import com.jcraft.jsch.*; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.*; import java.util.Properties; @Slf4j public class SshTest { private String charset = "UTF-8"; // 设置编码格式 private static String userName = "kevin"; // 用户名 private static String passWord= "1"; // 登录密码 private static String host = "192.168.10.101"; // 主机IP private static int port = 22; //默认端口 private static JSch jsch; private static Session session; private static ChannelSftp channelSftp; @BeforeAll public static void createConn() throws JSchException { JSch.setLogger(new Log4JSch()); // detail log for JSch. jsch = new JSch(); // jsch = new KeyGen().keyGenTest(); // 密钥方式 jsch.setKnownHosts("C:\\Users\\Admin\\.ssh\\known_hosts"); // jsch.addIdentity("~/.ssh/id_rsa", "~/.ssh/id_rsa.pub", null); // jsch.addIdentity("C:\\Users\\Admin\\.ssh\\id_rsa", "C:\\Users\\Admin\\.ssh\\id_rsa.pub", null); String privKeyPath = "C:\\Users\\Admin\\.ssh\\id_rsa"; jsch.addIdentity(privKeyPath); session = jsch.getSession(userName, host, port); // 密码方式 // session.setPassword(passWord); Properties config = new Properties(); /* * 在代码里需要跳过检测。否则会报错找不到主机 * Test ignored. * com.jcraft.jsch.JSchException: UnknownHostKey: 192.168.10.101. RSA key fingerprint is 10:92:98:45:d2:ea:6b:8f:c1:43:e5:df:86:e5:ae:3c */ config.put("StrictHostKeyChecking", "no"); session.setConfig(config); // 为Session对象设置properties int timeout = 30000; session.setTimeout(timeout); // 设置timeout时间 session.connect(); // 通过Session建立与远程服务器的连接回话 log.info("connect server host: " + host); } /** * 关闭连接 */ @AfterAll public static void disconnect(){ log.info("disconnect..."); if (channelSftp != null && channelSftp.isConnected()) { channelSftp.disconnect(); } if(session != null && session.isConnected()){ session.disconnect(); } } @Test public void downloadFile() throws JSchException, FileNotFoundException, SftpException { channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); log.info("start download channel file!"); String directory = "/tmp"; channelSftp.cd(directory); String saveDir = "D:\\desktop\\"+System.currentTimeMillis()+".txt"; File file = new File(saveDir); String downloadFile = "Test.java"; channelSftp.get(downloadFile, new FileOutputStream(file)); log.info("Download Success!"); channelSftp.disconnect(); log.info("end execute channel sftp!"); } @Test public void uploadFile() throws JSchException, SftpException, FileNotFoundException { channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); log.info("start upload channel file!"); String directory = "/tmp"; channelSftp.cd(directory); File file = new File("D:\\desktop\\Test.java"); channelSftp.put(new FileInputStream(file), file.getName().replace(".", System.currentTimeMillis()+".")); log.info("Upload Success!"); channelSftp.disconnect(); log.info("end execute channel sftp!"); } @Test public void execShell() throws JSchException, IOException { ChannelExec channelExec = (ChannelExec) session.openChannel("exec"); String cmd = "pwd"; channelExec.setCommand(cmd); //添加传入进来的shell命令 channelExec.setErrStream(System.err);//通道连接错误信息提示 channelExec.connect(); log.info("start execute channel command!"); try(BufferedReader in = new BufferedReader(new InputStreamReader(channelExec.getInputStream()))) { String msg; log.info("start read!"); while ((msg = in.readLine()) != null) { log.info("命令返回信息:{}", msg); } } catch (IOException e) { e.printStackTrace(); } channelExec.disconnect(); log.info("end execute channel command!"); } }
JSch 详细日志实现。
JSch.setLogger(new Log4JSch());
import com.jcraft.jsch.Logger; import java.util.HashMap; public class Log4JSch implements Logger { private static HashMap<String, String> name = new HashMap(); static { name.put(String.valueOf(DEBUG), "DEBUG"); name.put(String.valueOf(INFO), "INFO"); name.put(String.valueOf(WARN), "WARN"); name.put(String.valueOf(ERROR), "ERROR"); name.put(String.valueOf(FATAL), "FATAL"); } @Override public boolean isEnabled(int i) { return true; } @Override public void log(int level, String message) { System.err.println(name.get(String.valueOf(level)) + ": " + message); } }
问题1
com.jcraft.jsch.JSchException: invalid privatekey: [B@17f7cd29
查看id_rsa文件,内容如下
-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC... ... ... ...MAECAwQF -----END OPENSSH PRIVATE KEY-----
解决方案
Jsch好像不支持上面的私钥格式,要解决这个问题,我们可以使用ssh-keygen将私钥格式转换为RSAorpem模式,再次运行上面的程序。
$ ssh-keygen -p -f ~/.ssh/id_rsa -m pem
重新检查私钥内容,它应该以BEGIN RSA.
-----BEGIN RSA PRIVATE KEY----- MIIG4wIBAAK... ... ... ...E428GBDI4 -----END RSA PRIVATE KEY-----
再次尝试连接正常。
Admin@DESKTOP-91JEC09 MINGW64 ~ $ ssh kevin@hadoop101 Last login: Wed Oct 20 14:28:41 2021 from 192.168.10.1 [kevin@hadoop101 ~]$ client_loop: send disconnect: Connection reset by peer Admin@DESKTOP-91JEC09 MINGW64 ~ $ ssh-keygen -p -f C:\\Users\\Admin\\.ssh\\id_rsa -m pem Key has comment 'Admin@DESKTOP-91JEC09' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase. Admin@DESKTOP-91JEC09 MINGW64 ~ $ ssh kevin@hadoop101 Last login: Wed Oct 20 15:43:57 2021 from 192.168.10.1
参考文档:https://mkyong.com/java/jsch-invalid-privatekey-exception/http://www.jcraft.com/jsch/
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。