踩坑记录:java连接ssh的问题

news2024/11/27 6:18:35

目录

  • 概述
  • 一、第一个
    • 问题
    • 解决
  • 二、第二个
    • 问题
    • 分析
    • 解决
  • 三、第三个
    • 问题
    • 分析
    • 解决
  • 第四个
    • 问题
    • 解决

概述

手里有个CS架构的老系统,服务端要用SSH的方式传文件。没想到写了两天!遇到一堆问题,于是记录下。(老系统真恶心啊!)

一、第一个

问题

一开始使用原有的jsch包,但是ssh连不上,查资料后发现,服务器的ssh版本升级了,而且中央仓库的jsch包十几年不更新了,缺少很多密钥算法。

解决

改为使用apache的sshd包,我看一直有更新,因为线上服务器的ssh更高,于是用了比较新的版本。而且需要三个包,详细代码后面有。
sshd-core
sshd-sftp
sshd-common (这里和第二个坑有关!)

二、第二个

问题

使用sshd后,本地测试没问题,而放到测试服务器,服务端就一直报找不到sshd下面的ClientSession。

分析

因为是ClassLoader报的,原以为是二次代理,导致的ClassLoader无法获取第二次代理的外部jar(老架构的service全是用代理模式获取的,之前遇到过因二次代理导致service中无法获取hutool的问题)。后来想想这里不存在二次代理的问题,应该就只是ClassLoader获取外部jar包,于是找了下这个类,谁知。。(这里是idea用maven看的,netbean看起来实在麻烦)
在这里插入图片描述
core和common都有org.apache.sshd.client包!ClientSession在core里(不理解为啥不都装到core里!)
ClassLoader会先去找上面的common包找org.apache.sshd.client.ClientSession,找不到就不接着找了。

解决

用URLClassLoader去指定加载core里的ClientSession,但是想想太麻烦算了,于是准备把ssh传文件写成脚本,service去调用脚本的方式。

三、第三个

问题

开始写脚本,因为服务器没有go环境,python也有各种问题不想用,就用java写了个脚本。

import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.kex.DHGClient;
import org.apache.sshd.client.kex.DHGEXClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.scp.client.ScpClient;
import org.apache.sshd.scp.client.ScpClientCreator;

import java.util.Arrays;

/**
 * ssh执行器
 * 
 * @author zilong
 * @date 2023/12/14
 **/
public class SshExcute {
    
    public static void main(String args[]) {
        String username = null;
        String password = null;
        String ip = null;
        String sourcePath = null;
        String targetPath = null;
        String fileName = null;
        if (args[0] != null) {
            username = args[0];
        }
        if (args[1] != null) {
            password = args[1];
        }
        if (args[2] != null) {
            ip = args[2];
        }
        if (args[3] != null) {
            sourcePath = args[3];
        }
        if (args[4] != null) {
            targetPath = args[4];
        }
        if (args[5] != null) {
            fileName = args[5];
        }
        sendFile(
                username,
                password,
                ip,
                sourcePath,
                targetPath,
                fileName
        );
    }
    
    public static boolean sendFile (
            String username, String password, String ip, String sourcePath,
            String targetPath, String fileName
    ) {
        Security.addProvider(new BouncyCastleProvider());
        int port = 22;
        try {
            sourcePath = sourcePath + "/";
            String osName = System.getProperty("os.name");
            if (osName.toUpperCase().contains("WINDOWS")) {
                sourcePath = sourcePath.replaceAll("/", "\\\\");
            }
            String source = sourcePath + fileName;
            String target = targetPath + "/" + fileName;
            SshClient client = SshClient.setUpDefaultClient();
            client.start();

            ClientSession session = client.connect(username, ip, port).verify().getSession();
            session.addPasswordIdentity(password);
            boolean isSuccess = session.auth().verify().isSuccess();

            if (isSuccess) {
                ScpClientCreator creator = ScpClientCreator.instance();
                ScpClient scpClient = creator.createScpClient(session);

                System.out.println("Scp beginning...");
                scpClient.upload(source, target, ScpClient.Option.Recursive);
                System.out.println("Scp finished...");

                if (scpClient != null) {
                    scpClient = null;
                }

                if (session != null && session.isOpen()) {
                    session.close();
                }
                if (client != null && client.isOpen()) {
                    client.stop();
                    client.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}
java.lang.IllegalArgumentException: KeyExchangeFactories not set
	at org.apache.sshd.common.util.ValidateUtils.createFormattedException(ValidateUtils.java:213)
	at org.apache.sshd.common.util.ValidateUtils.throwIllegalArgumentException(ValidateUtils.java:179)
	at org.apache.sshd.common.util.ValidateUtils.checkTrue(ValidateUtils.java:174)
	at org.apache.sshd.common.util.ValidateUtils.checkNotNullAndNotEmpty(ValidateUtils.java:80)
	at org.apache.sshd.common.helpers.AbstractFactoryManager.checkConfig(AbstractFactoryManager.java:513)
	at org.apache.sshd.client.SshClient.checkConfig(SshClient.java:389)
	at org.apache.sshd.client.SshClient.start(SshClient.java:450)
	at Ss.sendFile(Ss.java:81)
	at Ss.main(Ss.java:46)

分析

debug看源码
在这里插入图片描述本地测试是有这些密钥算法的,但是服务器上没有,不知道从哪获取的,手动加上试试

在这里插入图片描述又报错
java.security.NoSuchAlgorithmException: Algorithm ECDH not avaliable
感觉还是得从源头下手,应该是服务器缺少相关环境,于是百度,发现是jre缺少加密算法相关的包导致的,那么手动加下就好了。
The Bouncy Castle Crypto package

解决

import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.kex.DHGClient;
import org.apache.sshd.client.kex.DHGEXClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.scp.client.ScpClient;
import org.apache.sshd.scp.client.ScpClientCreator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Security;
import java.util.Arrays;

/**
 * ssh执行器
 * 
 * @author zilong
 * @date 2023/12/14
 **/
public class SshExcute {
    
    public static void main(String args[]) {
        String username = null;
        String password = null;
        String ip = null;
        String sourcePath = null;
        String targetPath = null;
        String fileName = null;
        if (args[0] != null) {
            username = args[0];
        }
        if (args[1] != null) {
            password = args[1];
        }
        if (args[2] != null) {
            ip = args[2];
        }
        if (args[3] != null) {
            sourcePath = args[3];
        }
        if (args[4] != null) {
            targetPath = args[4];
        }
        if (args[5] != null) {
            fileName = args[5];
        }
        sendFile(
                username,
                password,
                ip,
                sourcePath,
                targetPath,
                fileName
        );
    }
    
    public static boolean sendFile (
            String username, String password, String ip, String sourcePath,
            String targetPath, String fileName
    ) {
        Security.addProvider(new BouncyCastleProvider());
        int port = 22;
        try {
            sourcePath = sourcePath + "/";
            String osName = System.getProperty("os.name");
            if (osName.toUpperCase().contains("WINDOWS")) {
                sourcePath = sourcePath.replaceAll("/", "\\\\");
            }
            String source = sourcePath + fileName;
            String target = targetPath + "/" + fileName;
            SshClient client = SshClient.setUpDefaultClient();
            client.setKeyExchangeFactories(Arrays.<KeyExchangeFactory>asList(
                    DHGClient.newFactory(BuiltinDHFactories.ecdhp521),
                    DHGClient.newFactory(BuiltinDHFactories.ecdhp384),
                    DHGClient.newFactory(BuiltinDHFactories.ecdhp256),
                    DHGEXClient.newFactory(BuiltinDHFactories.dhgex256),
                    DHGClient.newFactory(BuiltinDHFactories.dhg18_512),
                    DHGClient.newFactory(BuiltinDHFactories.dhg17_512),
                    DHGClient.newFactory(BuiltinDHFactories.dhg16_512),
                    DHGClient.newFactory((BuiltinDHFactories.dhg15_512)),
                    DHGClient.newFactory(BuiltinDHFactories.dhg14_256)));
            client.start();

            ClientSession session = client.connect(username, ip, port).verify().getSession();
            session.addPasswordIdentity(password);
            boolean isSuccess = session.auth().verify().isSuccess();

            if (isSuccess) {
                ScpClientCreator creator = ScpClientCreator.instance();
                ScpClient scpClient = creator.createScpClient(session);

                System.out.println("Scp beginning...");
                scpClient.upload(source, target, ScpClient.Option.Recursive);
                System.out.println("Scp finished...");

                if (scpClient != null) {
                    scpClient = null;
                }

                if (session != null && session.isOpen()) {
                    session.close();
                }
                if (client != null && client.isOpen()) {
                    client.stop();
                    client.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}

第四个

问题

java运行shell命令

Process p = Runtime
                .getRuntime()
                .exec("nohup java -Djava.ext.dirs=nosignlib SshExcute " +
                        "root root 192.168.1.15 /file /file a.txt >ssh.out &");
int rc = p.waitFor();
if (rc != 0) {
	InputStream errorStream = p.getErrorStream();
	BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
	String line;
	while ((line = reader.readLine()) != null) {
	    System.out.println(line);
	}
}

遇到了各种问题,有rc是0,但是没执行的,还有其他错误。

解决

java里执行nohup命令,会卡到那无法退出,并且很多问题可以通过sh运行脚本来解决,于是封装个脚本

# ssh_excute.sh
nohup java -Djava.ext.dirs=nosignlib SshExcute $1 $2 $3 $4 $5 $6 >ssh.out &
echo "excute completed..."
exit 0

对应java代码
1、必须用绝对路径,不然会找不到脚本。
2、必须用数组的构造器。字符串的构造器,底层会因特殊字符,将命令转换错误。
3、必须带 -c,要不然底层会把后面命令按空格截断。

String c = "/xxx/ssh_excute.sh root root 192.168.1.15 /file /file a.txt"
String[] command = {"/bin/sh", "-c", c};
ProcessBuilder pb = new ProcessBuilder(command);
p = pb.start();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1318787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

msvcp140.dll丢失怎样修复?全面分析msvcp140.dll的修复方法

在执行特定程序时&#xff0c;有可能遭遇msvcp140.dll文件遗失的困扰&#xff0c;此时该如何处理呢&#xff1f;此次将为您讲述面临此类问题的有效解决方案&#xff0c;涉及到多种修复方法&#xff0c;其中包括利用DLL修复工具进行操作。您可依据个人需求选择相应的修复方式&am…

学习Java第70天,过滤器Filter简介

过滤器概述 Filter,即过滤器,是JAVAEE技术规范之一,作用目标资源的请求进行过滤的一套技术规范,是Java Web项目中最为实用的技术之一 Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口 Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和…

用GitBook制作自己的网页版电子书

用GitBook制作自己的网页版电子书 前言 几年前阅读过其他人用GitBook创建的文档&#xff0c;可以直接在浏览器中打开&#xff0c;页面干净整洁&#xff0c;非常清爽&#xff0c;至今印象深刻。 GitBook非常适合用来为个人或团队制作文档&#xff0c;对于我这种偶尔写博客的人…

Vue 实现一个弹出框,允许用户输入信息,并在确认时将输入的信息进行输出到控制台

父组件用来点击按钮弹出弹出框 <!--ParentComponent.vue--> <template><div><button click"showPopupV">点我会有个弹出框&#xff01;&#xff01;&#xff01;</button><PopupComponent v-if"showPopup" :data"p…

java-sec-code中重定向

重定向 状态码3xx 存在问题的代码段 GetMapping("/redirect") public String redirect(RequestParam("url") String url) {return "redirect:" url; }用户访问/redirect路径时&#xff0c;redirect方法会获取web请求中的url参数内容&#xff0…

leetcode算法题:省份数量

leetcode算法题547 链接&#xff1a;https://leetcode.cn/problems/number-of-provinces 题目 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间…

EasyExcel 简单导入

前边写过使用easyexcel进行简单、多sheet页的导出。今天周日利用空闲写一下对应简单的导入。 重点&#xff1a;springboot、easyExcel、桥接模式&#xff1b; 说明&#xff1a;本次使用实体类student&#xff1a;属性看前边章节内容&#xff1b; 1、公共导入service public …

yarn历史日志_配置文件

yarn历史日志yarn配置文件yarn执行任务 1.3. YARN的历史日志 1.3.1. 历史日志概述 我们在YARN运行MapReduce的程序的时候&#xff0c;任务会被分发到不同的节点&#xff0c;在不同的Container内去执行。如果一个程序执行结束后&#xff0c;我们想去查看这个程序的运行状态呢…

GitHub入门介绍:从小白到大佬的旅程

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

动态规划学习——通符串匹配,正则表达式

目录 ​编辑 一&#xff0c;通符串匹配 1.题目 2.题目接口 3&#xff0c;解题思路及其代码 二&#xff0c;正则表达 1.题目 2.题目接口 3.解题思路及其代码 三&#xff0c;交错字符串 1.题目 2&#xff0c;题目接口 3.解题思路及其代码 一&#xff0c;通符串匹配 1…

docker使用详解

介绍 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。 Docker基于轻量级虚拟化技术&#xff0c;整个项目基于Go语言开…

2024最新FL Studio21.2MAC电脑版中文版下载安装步骤教程

FL Studio 简称FL&#xff0c;全称Fruity Loops Studio&#xff0c;因此国人习惯叫它"水果"。目前最新版本是FL Studio21.1.1.3750版本&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破…

MNIST内置手写数字数据集的实现

torchvision库 torchivision库是PyTorch中用来处理图像和视频的一个辅助库&#xff0c;接下来我们就会使用torchvision库加载内置的数据集进行分类模型的演示 为了统一数据加载和处理代码&#xff0c;PyTorch提供了两个类用于处理数据加载&#xff0c;他们分别是torch.utils.…

Typescript中Omit数据类型的理解

在 TypeScript 中&#xff0c;Omit 是一个内置的工具类型&#xff0c;它用于从对象类型中排除指定的属性&#xff0c;并返回剩余的属性。 Omit 的语法如下所示&#xff1a; type Omit<T, K> Pick<T, Exclude<keyof T, K>>;其中&#xff0c;T 表示原始类型…

Leetcode刷题笔记题解(C++):224. 基本计算器

思路&#xff1a; step 1&#xff1a;使用栈辅助处理优先级&#xff0c;默认符号为加号。 step 2&#xff1a;遍历字符串&#xff0c;遇到数字&#xff0c;则将连续的数字字符部分转化为int型数字。 step 3&#xff1a;遇到左括号&#xff0c;则将括号后的部分送入递归&#x…

面向对象三大特征——继承

目录 1. 概述 2. 继承的限制 2.1 单继承 2.2 访问修饰符 2.3 . final 3. 重写 4. super 4.1super的作用 4.2访问父类的成员和被重写方法 4.3调用父类的构造器 1. 概述 多个类中存在相同属性和行为时&#xff0c;将这些内容抽取到单独一个类中&#xff0c;那么就无需在…

DeciLM-7B:突破极限,高效率、高精准度的70亿参数AI模型

引言 在人工智能领域&#xff0c;语言模型的发展速度令人瞩目。Deci团队最近推出了一款具有革命性意义的语言模型——DeciLM-7B。这款模型在速度和精确度上都实现了显著的突破&#xff0c;以其70亿参数的规模&#xff0c;在语言模型的竞争中脱颖而出。 Huggingface模型下载&am…

C# 基本桌面编程(二)

一、前言 本章为C# 基本桌面编程技术的第二节也是最后一节。前一节在下面这个链接 C# 基本桌面编程&#xff08;一&#xff09;https://blog.csdn.net/qq_71897293/article/details/135024535?spm1001.2014.3001.5502 二、控件布局 1 叠放顺序 在WPF当中布局&#xff0c;通…

我与Datawhale的故事之长篇

Datawhale成员 作者&#xff1a;Datawhale团队成员 前 言 上周五周年文章发出后大家反响比较热烈&#xff1a; 我们与Datawhale背后的故事&#xff01; 本期给大家带来三篇长篇回忆 胡锐峰 我与Datawhale的故事 题记&#xff1a;我和你的相遇就像春风拂面&#xff0c;就像夏雨…

[原创][R语言]股票分析实战[2]:周级别涨幅趋势的相关性

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…