解决 no such file 的问题

1、概述

最近项目组来了个实习生,项目经理给他安排个任务,任务大致内容是将A服务上的文件A下载到服务B上。实习生也很努力,不过被这个事情折磨了好几天才完成。甲方给了一台机器,并给了账号,密码,但没有告诉端口号,实习生看这种下载文件就直接用了SFTP,端口号用了21,结果报no such file
在这里插入图片描述

2、sftp和ftp的区别是什么?

实习生既然提到了用sftp,那sftp和ftp的区别是什么呢?

  1. ftp基于tcp来传输文件,不提供任何安全通道来在主机之间传输文件;而sftp基于ssh来加密传输文件,会提供一个安全通道,用于在主机之间传输文件。
  2. ftp密码和数据以纯文本格式发送;sftp以二进制的形式传递。
    什么是FTP?
FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。
FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。
在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议。

什么是SFTP?

SFTP是一种安全的文件传输协议,一种通过网络传输文件的安全方法;它确保使用私有和安全的数据流来安全地传输数据。
SFTP要求客户端用户必须由服务器进行身份验证,并且数据传输必须通过安全通道(SSH)进行,即不传输明文密码或文件数据。它允许对远程文件执行各种操作,有点像远程文件系统协议。SFTP允许从暂停传输,目录列表和远程文件删除等操作中恢复。

SFTP和FTP之间的区别

SFTP和FTP非常相似,都支持批量传输(一次传输多个文件),文件夹/目录导航,文件移动,文件夹/目录创建,文件删除等。但还是存在着差异,下面我们来看看SFTP和FTP之间的区别。
1、安全通道
FTP 不提供任何安全通道来在主机之间传输文件;而SFTP协议提供了一个安全通道,用于在网络上的主机之间传输文件。
2、使用的协议
FTP使用TCP / IP协议。而,SFTP是SSH协议的一部分,它是一种远程登录信息。
3、链接方式
FTP使用TCP端口21上的控制连接建立连接。而,SFTP是在客户端和服务器之间通过SSH协议(TCP端口22)建立的安全连接来传输文件。
4、安全性
FTP密码和数据以纯文本格式发送,大多数情况下是不加密的,安全性不高。而,SFTP会在发送之前加密数据,二进制的形式传递,是无法“按原样”阅读的,安全性较高。
FTP 基于TCP来传输文件,明文传输用户信息和数据。
SFTP 基于SSH来加密传输文件,可靠性高,可断点续传。

3、问题分析

在处理问题前首先要搞清楚当前提供的账号设置与权限问题。大家可参考看下这篇文章。那肯定要关注链接方式,当时这个实习生居然用的是 21 端口。意识到问题后也改了 端口号为 22 再次访问还是不行,依然提示 no such file
实习生使用的代码片段:

引入jsch依赖

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version> <!-- 使用适当的版本号 -->
</dependency>

具体下载逻辑

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SftpDownloadExample {
    private static final Logger log = LoggerFactory.getLogger(SftpDownloadExample.class);

    public void downloadFile(String user, String password, String host, int port, String remoteFile, String localDir, String localFileName) {
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp sftpChannel = null;

        try {
            // 设置会话超时时间为60秒(60000毫秒)
            int sessionTimeout = 60000;
            
            // 创建会话
            session = jsch.getSession(user, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setTimeout(sessionTimeout);
            session.connect();
            
            // 打开 SFTP 通道
            Channel channel = session.openChannel("sftp");
            channel.connect();
            sftpChannel = (ChannelSftp) channel;
            
            // 下载文件
            log.info("local:{}", localDir + localFileName);
            sftpChannel.get(remoteFile, localDir + localFileName);
            String localTempFilePath = localDir + localFileName;
            log.info("sftpChannel.get() localTempFilePath:{}", localTempFilePath);
            
        } catch (Exception e) {
            log.error("Error during SFTP operation: {}", e.getMessage(), e);
            throw new RuntimeException("SFTP operation failed", e);
        } finally {
            // 关闭 SFTP 通道
            if (sftpChannel != null && sftpChannel.isConnected()) {
                sftpChannel.exit();
            }
            
            // 关闭会话
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    }
}
上述代码解析
1、添加了错误处理来捕获下载和上传过程中可能发生的异常,并在控制台输出错误信息。
在 finally 块中,检查通道和会话是否已连接,以确保只关闭那些已成功打开的资源。

2、请注意,这个示例代码禁用了 StrictHostKeyChecking,这在生产环境中是不推荐的做法,因为它会使得中间人攻击变得更加容易。在实际应用中,你应该考虑如何安全地处理主机密钥验证。

3、超时时间的设置,这些设置可能因 JSch 版本而异,建议查阅最新的 JSch 文档以获取准确的设置方法。此外,您应该根据您的网络环境和具体需求来调整这些超时值。

此时一位老同学说了句我们是docker部署的,那下载的远程目录是否做了映射呢?从实习生的表情看肯定是没有,下面简单说下

在使用Docker容器时,您可以使用 -p 选项来映射端口,使用 -v 选项来映射文件目录。这些选项在运行容器时(使用 docker run 命令)指定,以便您可以从宿主机访问容器的服务和文件系统。

以下是一些基本的示例:

端口映射
如果您想要将宿主机的端口映射到容器的端口,可以使用 -p 选项。例如,将宿主机的80端口映射到容器的80端口:
docker run -p 80:80 nginx

这会将宿主机的80端口映射到容器内的80端口。您还可以指定不同的宿主机和容器端口:
docker run -p 8080:80 nginx
这将把宿主机的8080端口映射到容器内的80端口。

文件目录映射
如果您想要将宿主机的文件目录映射到容器的文件系统,可以使用 -v 选项。例如,将宿主机的 /data 目录映射到容器的 /data 目录:
docker run -v /data:/data my-container
这会将宿主机的 /data 目录挂载到容器中的 /data 目录。您还可以指定只读或读写模式:
docker run -v /data:/data:ro my-container
这将挂载宿主机的 /data 目录到容器中的 /data 目录,但容器将以只读模式访问它。

同时映射端口和文件目录
您可以在同一个 docker run 命令中同时使用 -p-v 选项:
docker run -p 8080:80 -v /data:/data my-container
这会将宿主机的8080端口映射到容器的80端口,并将宿主机的 /data 目录映射到容器的 /data 目录。

注意事项
确保映射的宿主机端口没有被其他服务占用。
如果您在容器中运行的是网络服务,确保它监听的是正确的端口(通常是 0.0.0.0)。
对于文件目录映射,确保宿主机上的目录存在,并且容器内的用户有适当的权限访问它。
使用端口和文件目录映射时,请考虑安全性,特别是当您公开服务或挂载敏感数据目录时。确保您的容器和网络配置符合最佳安全实践。

到了这里通过修改docker容器文件目录映射、修改了sftp请求的端口号再 发布环境后验证通过。事实证明解决问题的过程中要多考虑,多验证。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值