记FTP链接:Server Reply: SSH-2.0-OpenSSH_8.0

1.前言

之前使用的是apache.commons.net.ftp.FTP的链接方式.今天在linux上面重新部署FTP之后.上传文件时

org.apache.commons.net.MalformedServerReplyException: Could not parse response code.
Server Reply: SSH-2.0-OpenSSH_8.0

在这里插入图片描述

2.解决

1. 办法:使用com.jcraft.jsch.JSch提供的SSH

2.步骤

  1. 导入maven包
    官网地址:https://mvnrepository.com/artifact/com.jcraft/jsch
    <dependency>
        <groupId>com.jcraft</groupId>
        <artifactId>jsch</artifactId>
        <version>0.1.54</version>
    </dependency>

3.链接相关代码块

  1. 配置基本信息,我这边使用的yml文件引入的方式
	@Value("${ftp.ftpIp}")
    private String ftpIp;//IP
    @Value("${ftp.ftpBasepath}")
    private String ftpBasepath;//文件路径
    @Value("${ftp.imageBaseUrl}")
    private String imageBaseUrl;//下载地址
    @Value("${ftp.ftpPort}")
    private Integer ftpPort;//端口
    @Value("${ftp.ftpUsername}")
    private String ftpUsername; //FTP帐号
    @Value("${ftp.ftpPassword}")
    private String ftpPassword;//FTP密码
  1. 链接服务器代码
  /**
     * 连接服务器
     */
    public Map<String, Object> getConnect() throws Exception {
        Session session = null;
        Channel channel = null;
        ChannelSftp sftp = null;// sftp操作类
        JSch jsch = new JSch();//创建客户端
        session = jsch.getSession(ftpUsername, ftpPort + "", ftpPort);//连接属性
        session.setPassword(ftpPassword);//输入密码
        //设置
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no"); // 不验证 HostKey
        //激活设置
        session.setConfig(config);
        //登录
        try {
            session.connect();
        } catch (Exception e) {
            if (session.isConnected())
                session.disconnect();
            logger.error("连接服务器失败,请检查主机[" + ftpIp + "],端口[" + ftpPort
                    + "],用户名[" + ftpUsername + "],端口[" + ftpPort
                    + "]是否正确,以上信息正确的情况下请检查网络连接是否正常或者请求被防火墙拒绝.");
        }
        channel = session.openChannel("sftp");
        //打开通道
        try {
            channel.connect();
        } catch (Exception e) {
            if (channel.isConnected())
                channel.disconnect();
            logger.error("连接服务器失败,请检查主机[" + ftpIp + "],端口[" + ftpPort
                    + "],用户名[" + ftpUsername + "],密码是否正确,以上信息正确的情况下请检查网络连接是否正常或者请求被防火墙拒绝.");
        }
        //保存属性
        sftp = (ChannelSftp) channel;
        HashMap<String, Object> map = new HashMap<>();
        map.put("channel", channel);
        map.put("session", session);
        map.put("sftp", sftp);
        return map;
    }
  1. 断开连接
 /**
     * 断开连接
     */
    public static void disConn(HashMap<String, Object> map) throws Exception {
        Session session = (Session) map.get("session");
        Channel channel = (Channel) map.get("channel ");
        ChannelSftp sftp = (ChannelSftp) map.get("sftp");
        if (null != sftp) {
            sftp.disconnect();
            sftp.exit();
        }
        if (null != channel) {
            channel.disconnect();
        }
        if (null != session) {
            session.disconnect();
        }
    }

4.文件操作相关代码

  1. 上传文件
  /**
     * 上传文件
     *
     * @param directory  上传的目录-相对于SFPT设置的用户访问目录,
     *                   为空则在SFTP设置的根目录进行创建文件(除设置了服务器全磁盘访问)
     * @param uploadFile 要上传的文件全路径
     */
    public void upload(String directory, String uploadFile) throws Exception {
        JschUtils jschUtils = new JschUtils();
        //建立连接
        Map<String, Object> map = jschUtils.getConnect();
        Session session = (Session) map.get("session");
        Channel channel = (Channel) map.get("channel ");
        ChannelSftp sftp = (ChannelSftp) map.get("sftp");
        try {
        try {
            sftp.cd(directory); //进入目录
        } catch (SftpException sException) {
            if (sftp.SSH_FX_NO_SUCH_FILE == sException.id) { //指定上传路径不存在
                sftp.mkdir(directory);//创建目录
                sftp.cd(directory);  //进入目录
            }
        }
        File file = new File(uploadFile);
        InputStream in = new FileInputStream(file);
        sftp.put(in, file.getName());
        in.close();  } catch (Exception e) {
            throw new Exception(e.getMessage(),e);
        } finally {
            disConn(map);
        }
    }
  1. 下载文件
   /**
     * 下载文件
     * @param directory 下载目录 根据SFTP设置的根目录来进行传入
     * @param downloadFile  下载的文件 
     * @param saveFile  存在本地的路径 
     */
    public static void download(String directory, String downloadFile,String saveFile) throws Exception {
        JschUtils jschUtils = new JschUtils();
        //建立连接
        Map<String, Object> map = jschUtils.getConnect();
        ChannelSftp sftp = (ChannelSftp) map.get("sftp");
        try {
            sftp.cd(directory); //进入目录
            File file = new File(saveFile);
            boolean bFile;
            bFile = false;
            bFile = file.exists();
            if (!bFile) {
                bFile = file.mkdirs();//创建目录
            }
            OutputStream out=new FileOutputStream(new File(saveFile,downloadFile));
            sftp.get(downloadFile, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            throw new Exception(e.getMessage(),e);
        } finally {
            disConn(map);
        }
    }

6.其他

这种方式是不支持创建多层目录的,需要一层一层去判断

  if (sftp.SSH_FX_NO_SUCH_FILE == sException.id) { //指定上传路径不存在
        //创建多层目录及判断
        String filedirurl = ftpBasepath + filePath;
        String[] dirs = filedirurl.split("/");
        String tempPath = "";//虚拟层
        for (String dir : dirs) {
            if (null == dir || "".equals(dir)) {
                continue;
            } else {
                tempPath += "/" + dir;
                try {
                    logger.info("检测目录[" + tempPath + "]");
                    sftp.cd(tempPath);
                } catch (SftpException ex) {
                    try {
                        logger.error("创建目录[" + tempPath + "]");
                        sftp.mkdir(tempPath);
                        sftp.cd(tempPath);
                        logger.error("进入目录[" + tempPath + "]");
                    } catch (SftpException e1) {
                        logger.error("创建目录[" + tempPath
                                + "]失败1,异常信息[" + e1.getMessage() + "]");
                    } catch (Exception e1) {
                        logger.error("创建目录[" + tempPath
                                + "]失败2,异常信息[" + e1.getMessage() + "]");
                    }
                } catch (Exception e1) {
                    logger.error("创建目录[" + tempPath + "]失败3,异常信息["
                            + e1.getMessage() + "]");
                }
            }
        }
        sftp.cd(ftpBasepath + filePath);  //进入目录
    }

5.结尾

  1. 上传下载:参考文章:https://blog.csdn.net/u012909738/article/details/74328669
  2. 多层目录 参考文章:https://blog.csdn.net/weixin_39921821/article/details/90646283
  3. 此文只有上传下载,与原文有一定冲突,酌情参考
OpenSSH 8.0 发布了,此版本缓解了 scp(1) 工具和协议漏洞 CVE-2019-6111,该漏洞此前我们之前报导过:知名文件传输协议 SCP 被曝存在 35 年历史的安全漏洞。 将文件从远程系统复制到本地目录时,SCP 客户端无法验证 SCP 服务器返回的对象是否与请求的东西一致,这使得攻击者可以使用恶意服务器控制的内容创建或破坏本地文件。 OpenSSH 8.0 的缓解措施添加了客户端检查,查看从服务器发送的文件名与命令行请求是否匹配。 SCP 协议已经过时,不灵活且不易修复,OpenSSH 官方建议使用更现代的协议进行文件传输,如 sftp 和 rsync。 此版本新特性包括: ssh(1)、ssh-agent(1)、ssh-add(1):PKCS#11 token 中添加对 ECDSA 密钥的支持。 ssh(1)、sshd(8):基于 Streamlined NTRU Prime 4591^761 和 X25519 的组合,添加实验性量子计算抗性密钥交换方法。 ssh-keygen(1):将默认 RSA 密钥大小增加到 3072 位。 ssh(1):允许“PKCS11Provider = none”覆盖 ssh_config 中 PKCS11Provider 指令的后续实例。 ssh(1):提示是否录制新主机密钥时,输入密钥指纹作为“yes”。 ssh-keygen(1):在单个命令行调用上签名多个证书时,允许自动递增证书序列号。 scp(1)、sftp(1):接受 -J 选项作为 scp 和 sftp 命令行上 ProxyJump 的别名。 ssh-agent(1)、ssh-pkcs11-helper(8)、ssh-add(1):接受“-v”命令行标志以增加输出的详细程度;将详细标志传递给子进程,例如从 ssh-agent 启动的 ssh-pkcs11-helper。 ssh-add(1):添加“-T”选项以允许通过执行签名和验证来测试代理中的密钥是否可用。 sshd(8):在 PAM 环境中暴露 $SSH_CONNECTION。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值