• 推荐使用Hutool的Jsch工具包(它用的连接池的技术)

一、SSH远程连接服务器

1、SSH(Secure Shell)主要有两大功能

1、远程命令执行:SSH允许用户在远程主机上执行命令。用户可以通过SSH连接到远程主机,然后在命令行界面输入命令,就像直接在远程主机的控制台上操作一样。这是SSH最常用的功能,它使得用户可以方便地管理和维护远程主机。

2、安全的文件传输:SSH提供了SFTP(SSH File Transfer Protocol)和SCP(Secure Copy)两种文件传输协议,用于在本地主机和远程主机之间安全地传输文件。这两种协议都使用SSH的安全机制,可以保护文件在传输过程中的安全性和完整性。

3、除了这两大功能,SSH还有一些其他的功能,例如端口转发和动态端口转发(也称为SOCKS代理),它们可以用来建立安全的网络连接,或者绕过网络限制。

二、JNA、Process和JSch

  • JNA

JNA主要用于在Java程序中调用本地库的函数,而不是用于远程连接到其他系统。如果你的Java程序正在Linux系统上运行,你可以使用JNA来调用Linux的本地库函数,包括那些可以获取文件和文件夹路径的函数。然而,如果你的Java程序正在一个系统(如Windows)上运行,你不能使用JNA来连接到另一个系统(如Linux)。

  • JSch

如果你需要从一个运行在Windows上的Java程序连接到一个Linux系统,你可能需要使用其他的工具或库。例如,你可以使用SSH(安全壳层)来远程连接到Linux系统,然后执行命令来获取文件和文件夹的路径。在Java中,有一些库可以帮助你使用SSH,如JSch和Apache MINA SSHD。

简单理解JNA、Process和JSch

  • JNA(Java Native Access)和Process类都是Java中与本地系统交互的工具。JNA允许Java代码直接调用本地(C/C++)库的函数,而Process类则允许Java代码启动和控制操作系统的进程,例如执行shell命令。(JNA和Process是Java调用系统(Windows、Linux等)的本地函数,或者三方程序)

  • JSch是一个Java库,它提供了SSH(Secure Shell)的Java实现,允许Java程序通过SSH协议连接到远程系统(如Linux)。一旦连接成功,你可以通过JSch执行远程命令,上传和下载文件,就像直接在远程系统上操作一样。(JSch则是Java连接系统(Windows、Linux等)的工具,比如连接上Linux后,相当于直接操作Linux一样)

三、Java使用SSH的包

3.1、JSch和Apache MINA SSHD


JSch和Apache MINA SSHD都是优秀的SSH库,它们各有优点,选择哪一个主要取决于你的具体需求。

JSch是一个成熟且广泛使用的库,它提供了SSH2的完整实现,包括SFTP,SCP,端口转发等功能。JSch的API相对简单,易于使用,而且JSch的社区活跃,有大量的教程和示例代码可供参考。

Apache MINA SSHD则是一个更现代的库,它基于Apache MINA,一个高性能的网络应用框架。MINA SSHD提供了SSH2的完整实现,包括SFTP,SCP,端口转发等功能。MINA SSHD的API设计更现代,更符合Java的编程习惯,而且MINA SSHD支持异步非阻塞IO,对于需要处理大量并发连接的应用来说,可能会有更好的性能。

总的来说,如果你需要一个简单易用,社区支持好的SSH库,JSch可能是一个不错的选择。如果你需要一个设计现代,支持异步非阻塞IO的SSH库,或者你已经在使用Apache MINA,那么MINA SSHD可能更适合你。


3.2、JSch的四种认证机制:

  1. 密码(本文使用):这是最常见的身份验证方式,用户需要提供用户名和密码来进行身份验证。

  2. 公钥:在这种方式中,用户需要提供一个私钥,JSch会使用这个私钥来进行身份验证。这种方式通常比基于密码的身份验证更安全,因为私钥通常比密码更难被猜测或者破解。

  3. 键盘交互:这种方式允许服务器发送一个或多个提问给客户端,客户端需要回答这些问题来进行身份验证。这种方式可以用来实现一些复杂的身份验证流程,例如一次性密码,或者多因素身份验证。

  4. GSSAPI:GSSAPI是一种用于安全通信的API,它支持各种不同的身份验证机制,例如Kerberos。JSch可以使用GSSAPI来进行身份验证,但这需要额外的库支持。

四、JSch实现登录Linux,远程命令执行、SFTP下载和上传文件

4.1、导包Jsch

  • 官方的包上次更新18年(本文使用)
    // jsch包
implementation 'com.jcraft:jsch:0.1.55'

4.2、Jsch工具类

package com.cc.jschdemo.utils;

import com.jcraft.jsch.*;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component; import javax.annotation.PreDestroy;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*; /**
* <p>JSch工具类</p>
* <li>交给spring管理:每个使用的地方都是单例,都是单独的这个类。(new 也可以)</li>
*
* <li>所有方法都没有关闭(连接、会话),需要使用方自己关闭</li>
*
* @author CC
* @since 2023/11/8
*/
@Data
@Component
public class JSchUtil { //缓存session会话
private Session session; //通道:执行命令
private ChannelExec channelExec;
//通道:SFTP
private ChannelSftp channelSftp;
//通道:执行复杂Shell命令
private ChannelShell channelShell; //登陆Linux服务器
public void loginLinux(String username, String password, String host, Integer port) {
try {
//每次都会重新初始化session
if (Objects.isNull(session) || !session.isConnected()) {
JSch jsch = new JSch();
session = jsch.getSession(username, host, port);
session.setPassword(password); // 配置Session参数
Properties config = new Properties();
// 不进行公钥的检查
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// 设置连接超时时间(s/秒)
session.setTimeout(300);
}
if (!session.isConnected()) {
// 连接到远程服务器
session.connect();
}
}catch(Exception e){
throw new RuntimeException("连接Linux失败:" + e.getMessage());
}
} //执行命令:可以多次执行,然后必须调用关闭接口
public String executeCommand(String command) {
StringBuilder result = new StringBuilder();
BufferedReader buf = null;
try {
//每次执行都创建新的通道
channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setCommand(command); //正确的流中没有数据就走错误流中去拿。
InputStream in = channelExec.getInputStream();
InputStream errStream = channelExec.getErrStream();
channelExec.connect(); buf = new BufferedReader(new InputStreamReader(in));
String msg;
while ((msg = buf.readLine()) != null) {
result.append(msg);
} if (StringUtils.isBlank(result.toString())) {
buf = new BufferedReader(new InputStreamReader(errStream));
String msgErr;
while ((msgErr = buf.readLine()) != null) {
result.append(msgErr);
}
}
}catch(Exception e){
throw new RuntimeException("关闭连接失败(执行命令):" + e.getMessage());
}finally {
if (Objects.nonNull(buf)) {
try {
buf.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
return result.toString();
} /**
* 执行复杂shell命令
*
* @param cmds 多条命令
* @return 执行结果
* @throws Exception 连接异常
*/
public String execCmdByShell(List<String> cmds) { String result = "";
try {
channelShell = (ChannelShell) session.openChannel("shell"); InputStream inputStream = channelShell.getInputStream();
channelShell.setPty(true);
channelShell.connect();
OutputStream outputStream = channelShell.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
for (String cmd : cmds) {
printWriter.println(cmd);
}
printWriter.flush();
byte[] tmp = new byte[1024];
while (true) {
while (inputStream.available() > 0) {
int i = inputStream.read(tmp, 0, 1024);
if (i < 0) {
break;
}
String s = new String(tmp, 0, i);
if (s.contains("--More--")) {
outputStream.write((" ").getBytes());
outputStream.flush();
}
System.out.println(s);
}
if (channelShell.isClosed()) {
System.out.println("exit-status:" + channelShell.getExitStatus());
break;
}
//间隔1s后再执行
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
outputStream.close();
inputStream.close();
}catch(Exception e){
e.printStackTrace();
} return result;
} //下载除了云服务器的文件(你自己的服务器):因为云服务器,像阿里云服务器下载文件好像是一段一段给你的,不是一起给你。
public void downloadOtherFile(String remoteFileAbsolutePath, String fileName, HttpServletResponse response) {
try {
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); //获取输入流
InputStream inputStream = channelSftp.get(remoteFileAbsolutePath);
//直接下载到本地文件
// channelSftp.get(remoteFileAbsolutePath, "D:\\Develop\\Test\\studio-3t-x64.zip"); response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType("application/octet-stream;charset=".concat(StandardCharsets.UTF_8.name()));
response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=".concat(
URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
));
ServletOutputStream out = response.getOutputStream(); // 从InputStream输入流读取数据 并写入到ServletOutputStream输出流
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.flush();
out.close();
}catch(Exception e){
throw new RuntimeException("关闭连接失败(下载文件):" + e.getMessage());
}
} //下载云服务器的文件(因为云服务器传文件是一段一段的,所以不能直接像操作我们的服务器一样直接下载)(阿里云为例)
public void downloadCloudServerFile(String remoteFileAbsolutePath, String fileName, HttpServletResponse response) {
try {
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); //获取输入流
InputStream inputStream = channelSftp.get(remoteFileAbsolutePath); //阿里云应该是断点续传,后面研究…… }catch(Exception e){
throw new RuntimeException("关闭连接失败(下载文件):" + e.getMessage());
}
} //ls命令:获取文件夹的信息
public String ls(String path){
StringBuilder sb = new StringBuilder();
try {
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); Vector ls = channelSftp.ls(path);
Iterator iterator = ls.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
sb.append(next);
}
} catch (Exception e){
throw new RuntimeException(e.getMessage());
}
return sb.toString();
} //关闭通道:释放资源
private void closeChannel(){
//不为空,且已经连接:关闭
if (Objects.nonNull(channelExec)) {
channelExec.disconnect();
}
if (Objects.nonNull(channelSftp)) {
channelSftp.disconnect();
}
if (Objects.nonNull(channelShell)) {
channelShell.disconnect();
}
} /** 关闭通道、关闭会话:释放资源
* spring销毁前,关闭 所有会话 及 所有通道
*/
@PreDestroy
public void closeAll(){
System.out.println("我被销毁了。。。。。。。。。。。。。。。。。。。。。。"); this.closeChannel(); if (Objects.nonNull(session) && session.isConnected()) {
session.disconnect();
}
} }

4.2、使用Jsch工具类:执行命令

4.2.1、执行简单命令

package com.cc.jschdemo.web.controller;

import com.cc.jschdemo.utils.JSchUtil;
import com.jcraft.jsch.ChannelExec;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Arrays; /**
* <p></p>
*
* @author CC
* @since 2023/11/8
*/
@RestController
@RequestMapping("/jsch")
public class JSchController { @Resource
private JSchUtil jSchUtil; /** <p>执行命令<p>
**/
@GetMapping
public String executeCommand() {
//登陆(默认只连接5分钟,5分钟后销毁)
jSchUtil.loginLinux("服务器账号", "服务器密码", "服务器IP", 服务器端口);
//一、执行命令
String mkdir = jSchUtil.executeCommand("mkdir ccc");
String docker = jSchUtil.executeCommand("docker");
String dockerPs = jSchUtil.executeCommand("docker ps"); System.out.println(mkdir);
System.out.println(docker);
System.out.println(dockerPs); //执行完,关闭连接
jSchUtil.closeAll(); return docker;
}
}
  • 结果:
  • 多了一个文件夹

4.2.1、执行复杂的shell命令

   /** <p>执行命令<p>
**/
@PostMapping
public String execCmdByShell() {
//登陆(默认只连接5分钟,5分钟后销毁)
jSchUtil.loginLinux("服务器账号", "服务器密码", "服务器IP", 服务器端口);
//二、执行shell脚本(可以改造成传入的shell脚步)
jSchUtil.execCmdByShell(Arrays.asList("cd /", "ll" , "cd cc/", "mkdir ccccc222", "ll"));
//执行完,关闭连接
jSchUtil.closeAll(); return "docker";
}
  • 结果

4.3、使用Jsch工具类:下载文件

4.3.1、普通服务器下载

    //下载普通服务器的文件
@PutMapping
public void downloadOtherFile(HttpServletResponse response) {
//登陆(默认只连接5分钟,5分钟后销毁)
jSchUtil.loginLinux("服务器账号", "服务器密码", "服务器IP", 服务器端口);
//下载文件
jSchUtil.downloadOtherFile(
"/dev/libbb/studio-3t-x64.zip",
"studio-3t-x64.zip",
response
);
//执行完,关闭连接
jSchUtil.closeAll();
}

4.3.2、阿里云服务器下载

  • 博主很懒,没留下什么……

五、Hutool工具封装的JSch(推荐)

  • Hutool使用的是JSch连接池,推荐使用……
  • 博主比较懒,还没实现……

六、总结

参考:

https://www.jb51.net/article/264152.htm

https://www.jb51.net/article/264148.htm

SpringBoot使用JSch操作Linux的更多相关文章

  1. java使用Jsch实现远程操作linux服务器进行文件上传、下载,删除和显示目录信息

    1.java使用Jsch实现远程操作linux服务器进行文件上传.下载,删除和显示目录信息. 参考链接:https://www.cnblogs.com/longyg/archive/2012/06/2 ...

  2. Linux C 程序 文件操作(Linux系统编程)(14)

    文件操作(Linux系统编程) 创建一个目录时,系统会自动创建两个目录.和.. C语言实现权限控制函数 #include<stdio.h> #include<stdlib.h> ...

  3. [转] Springboot的数据库操作

    转载自:https://www.cnblogs.com/juncaoit/p/7789034.html springBoot的数据库操作 一:操作数据库起步 1.Spring-Data-Jpa JPA ...

  4. Linux课程---3、Linux远程登录和传输(操作Linux服务器软件)

    Linux课程---3.Linux远程登录和传输(操作Linux服务器软件) 一.总结 一句话总结: xshell:Xshell是一个强大的安全终端模拟软件 Xshell是一个强大的安全终端模拟软件, ...

  5. springboot学习-jdbc操作数据库--yml注意事项--controller接受参数以及参数校验--异常统一管理以及aop的使用---整合mybatis---swagger2构建api文档---jpa访问数据库及page进行分页---整合redis---定时任务

    springboot学习-jdbc操作数据库--yml注意事项--controller接受参数以及参数校验-- 异常统一管理以及aop的使用---整合mybatis---swagger2构建api文档 ...

  6. 远程操作Linux主机

    通过putty文件访问: 下载路径:https://the.earth.li/~sgtatham/putty/0.70/w32/putty-0.70-installer.msi 通过Python文件执 ...

  7. Windows下python3登陆和操作linux服务器

    一.环境准备 python3远程连接需要用到pycrytodome和paramiko库,其中后者依赖前者,所以按照顺序来安装 1. 安装pycrytodome 1 pip install pycryt ...

  8. 在Windows上使用终端模拟程序连接操作Linux以及上传下载文件

    在Windows上使用终端模拟程序连接操作Linux以及上传下载文件 [很简单,就是一个工具的使用而已,放这里是做个笔记.] 刚买的云主机,或者是虚拟机里安装的Linux系统,可能会涉及到在windo ...

  9. python paramiko通过远程操作linux

    python-paramiko通过远程操作linux 1. python-paramiko通过远程操作linux python3 远程操作linux 使用第三方paramiko库,对于实现运维自动部署 ...

  10. java利用Jsch实现在windows平台远程操作linux服务器

    说明:exec用于执行命令:sftp用于文件处理 package com.wyg.simple; import java.io.BufferedReader; import java.io.File; ...

随机推荐

  1. 开发必会系列:《深入理解JVM(第二版)》读书笔记

    一  开始前 HotSpot:http://xiaomogui.iteye.com/blog/857821 http://blog.csdn.net/u011521890/article/detail ...

  2. 《Effective Java》笔记

    2. 创建和销毁对象 1. 静态工厂方法替代构造器 优点: 名称清晰 每次调用不必new对象 可以返回原返回类型任意子类型对象 返回的对象可以随着调用而发生改变 返回的对象所属的类,在编写该静态工厂方 ...

  3. KingbaseES V8R6 等待事件之IO类BufFileRead BufFileWrite

    等待事件含义 当数据库创建临时文件时,会发生IO:BufFileRead和IO:BufFileWrite等待事件.当操作需要的内存比当前定义的work_mem内存参数更多时,会将临时数据写入磁盘永久存 ...

  4. FineReport 自定义工具栏样式

    虽然FR界面的工具栏已经很商业化,很好看了,但是总会有那么些需求希望你可以修改工具栏的样式. 修改工具栏样式的主要思路是: 通过JQ选择器选中需要调整的元素,然后修改他们的样式 接下来,我们尝试着对工 ...

  5. C++设计模式 -中介者模式(Mediator)

    接口隔离模式 在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题.甚至根本无法实现.采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案. 典型模式 Facade P ...

  6. .Net单元测试xUnit和集成测试指南(1)

    引言 在现代化的软件开发中,单元测试和集成测试是确保代码质量和可靠性的关键部分.ASP.NET Core 社区内提供了强大的单元测试框架,xUnit 是其中之一,它提供了简单.清晰和强大的测试功能,编 ...

  7. #贪心,二叉堆#洛谷 1954 [NOI2010] 航空管制

    题目 分析 首先考虑可行方案,很容易想到拓扑排序, 但是如果建正图第一类的限制有可能不能满足, 考虑第一类限制其实时间倒流就是在 \(T\) 时刻之后才能选它. 那么直接建反图然后 \(a_i\) 大 ...

  8. 使用OHOS SDK构建mimalloc

    参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone https://github.com/microsoft/mimalloc.git ...

  9. Go 编程语言详解:用途、特性、与 Python 和 C++ 的比较

    什么是Go? Go是一个跨平台.开源的编程语言 Go可用于创建高性能应用程序 Go是一种快速.静态类型.编译型语言,感觉上像动态类型.解释型语言 Go由Robert Griesemer.Rob Pik ...

  10. 帕鲁重大更新!macOS 竟然也能玩了

    近日,<幻兽帕鲁>迎来了 v0.2.1.0 大版本的更新. 本次更新的最大亮点是新实装的突袭头目系统.玩家可以在 "召唤祭坛" 献祭石板,从而召唤强大的突袭头目.其中, ...