linux搭建ftps(vsftpd),java代码测试上传下载

一、服务器安装

操作系统Ubuntu:

sudo apt-get install vsftpd

操作系统Centos:

sudo yum install -y vsftpd

##创建ftps用户,设置默认目录
useradd -d /home/ftp ftpname
passwd ftpuse123

##设置用户权限,不能登录
usermod -s /sbin/nologin ftpname 

##修改用户默认目录
usermod -d /ftp ftpname

## 备份原始配置文件
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak

################ vsftpd.conf ################

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
pam_service_name=ftp
idle_session_timeout=600
data_connection_timeout=120 
listen_port=10021
pasv_promiscuous=YES
pasv_enable=YES
pasv_min_port=18700
pasv_max_port=18790
port_enable=YES
#日志文件
xferlog_file=/var/log/xferlog
#使用标准文件日志
xferlog_std_format=YES
#是否允许上传二进制文件
ascii_upload_enable=YES
#是否允许下载二进制文件
ascii_download_enable=YES

#是否启用SSL,默认NO
ssl_enable=YES
#是否激活sslv2加密,默认NO
ssl_sslv2=YES
#是否激活sslv3加密,默认NO
ssl_sslv3=YES
#是否激活tls v1加密,默认NO
ssl_tlsv1=YES
#非匿名用户登陆时是否加密
force_local_logins_ssl=YES
#非匿名用户传输数据时是否加密
force_local_data_ssl=YES
#ssl证书位置
rsa_cert_file=/etc/vsftpd/.sslkey/vsftpd.pem

################ vsftpd.conf ################

## 证书生成地址,可自定义,配置文件中对应即可
mkdir -p /etc/vsftpd/.sslkey

sudo openssl req -new -x509 -nodes -days 3650 -out vsftpd.pem -keyout vsftpd.pem

##按提示输入相关信息即可




服务启动/重启/停止

systemctl start/restart/stop vsftpd

1.2 centos的安装方式

sudo yum install -y vsftpd
## 服务和配置文件都在/etc/vsftpd下
和Ubuntu有点区别,以上操作完成,使用外部工具可能会连不上,需要修改
1、修改/etc/pam.d/vsftpd

添加:auth       required     pam_nologin.so

在这里插入图片描述

2、如果想要root也可以远程登录
修改 /etc/vsftpd/ftpusers ,注释掉第一行 root

二、代码案例
切记不要使用3.1,有坑

	<dependency>
		<groupId>commons-net</groupId>
		<artifactId>commons-net</artifactId>
		<version>3.8.0</version>
	</dependency>
@Slf4j
public class SSLSessionReuseFtpsClient extends FTPSClient {
    /**
     * @param command the command to get
     * @param remote  the remote file name
     * @param local   the local file name
     * @return true if successful
     * @throws IOException on error
     * @since 3.1
     */
    @Override
    protected boolean _retrieveFile(String command, String remote, OutputStream local) throws IOException {
        Socket socket = _openDataConnection_(command, remote);
        if (socket == null) {
            return false;
        }
        final InputStream input;
        input = new BufferedInputStream(socket.getInputStream());
        // Treat everything else as binary for now
        try {
            Util.copyStream(input, local, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, false);
        } finally {
            Util.closeQuietly(input);
            Util.closeQuietly(socket);
        }
        // Get the transfer response
        return completePendingCommand();
    }

    @Override
    protected void _prepareDataSocket_(final Socket socket) throws IOException {
        if (socket instanceof SSLSocket) {
            // Control socket is SSL
            final SSLSession session = ((SSLSocket) _socket_).getSession();
            final SSLSessionContext context = session.getSessionContext();
            try {
                final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
                sessionHostPortCache.setAccessible(true);
                final Object cache = sessionHostPortCache.get(context);
                final Method method = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
                method.setAccessible(true);
                final String key = String.format("%s:%s", socket.getInetAddress().getHostName(), String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
                method.invoke(cache, key, session);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                // Not running in expected JRE
                log.error("No field sessionHostPortCache in SSLSessionContext");
            } catch (Exception e) {
                // Not running in expected JRE
                e.printStackTrace();
            }
        }

    }
}
@Slf4j
public class FtpsUtils {

    private static SSLSessionReuseFtpsClient ftpsClient = null;
    public static final String PATH_SUFFIX = "/";

    /**
     * 登录认证
     *
     * @return true/false
     */
    public static boolean login(String ip, int port, String username, String password) {
        try {
            //设置环境变量
            System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
            ftpsClient = new SSLSessionReuseFtpsClient();
            FTPClientConfig config = new FTPClientConfig();
            ftpsClient.configure(config);
            // 打印调用日志,调试时使用,上线后注释
            ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
            ftpsClient.setControlEncoding("utf-8");
            FtpsProperties ftpsProperties = BeanUtil.getBean(FtpsProperties.class);
            ftpsClient.connect(ip, port);
            ftpsClient.login(username, password);
            int reply = ftpsClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpsClient.disconnect();
                return false;
            }
            // 主动模式,PORT模式。通知客户端打开一个数据端口,服务端将连接到这个端口进行数据传输。
            // ftpsClient.enterRemotePassiveMode();
            // 被动模式,PASV模式。通知服务器打开一个数据端口,客户端将连接到这个端口进行数据传输。
            ftpsClient.enterLocalPassiveMode();
            // 流传输模式
            ftpsClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
            // 数据连接超时(以毫秒为单位),vsftpd配置文件默认120s
            ftpsClient.setDataTimeout(18000);
            // 数据通道保护级别
            ftpsClient.execPROT("P");
            ftpsClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpsClient.setBufferSize(1024);
            log.info("ftps连接成功....ip={},port={}", ip, port);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 上传文件
     *
     * @param directory 服务端路径
     * @param file      本地文件路径
     */
    public static boolean uploadFile(String directory, File file) {
        try {
            if (createDirectory(directory)) {
                ftpsClient.storeFile(file.getName(), new FileInputStream(file));
                ftpsClient.logout();
                log.info("附件上传成功!远程文件路径:{}", directory);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftpsClient.isConnected()) {
                try {
                    ftpsClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
     *
     * @param remote 目录
     */
    public static boolean createDirectory(String remote) {
        String directory = remote;
        try {
            if (!remote.endsWith(PATH_SUFFIX)) {
                directory = directory + PATH_SUFFIX;
            }
            // 如果远程目录不存在,则递归创建远程服务器目录
            if (!PATH_SUFFIX.equals(directory) && !ftpsClient.changeWorkingDirectory(directory)) {
                int start;
                int end;
                if (directory.startsWith(PATH_SUFFIX)) {
                    start = 1;
                } else {
                    start = 0;
                }
                end = directory.indexOf(PATH_SUFFIX, start);
                StringBuilder path = new StringBuilder();
                StringBuilder paths = new StringBuilder();
                do {
                    String subDirectory = remote.substring(start, end);
                    path.append(path).append(PATH_SUFFIX).append(subDirectory);
                    // 目录不存在就创建
                    if (!ftpsClient.changeWorkingDirectory(subDirectory)) {
                        if (ftpsClient.makeDirectory(subDirectory)) {
                            ftpsClient.changeWorkingDirectory(subDirectory);
                        }
                    }
                    paths.append(paths).append(PATH_SUFFIX).append(subDirectory);
                    start = end + 1;
                    end = directory.indexOf(PATH_SUFFIX, start);
                    // 检查所有目录是否创建完毕
                } while (end > start);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 下载文件
     *
     * @param directory 服务端路径
     * @param file      本地文件路径
     */
    public static boolean downloadFile(String directory, File file) {
        FileOutputStream fos = null;
        try {
            String[] listNames = ftpsClient.listNames(directory);
            for (String path : listNames) {
                if (path.endsWith(file.getName())) {
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    fos = new FileOutputStream(file);
                    ftpsClient.retrieveFile(path, fos);
                    log.info("文件下载成功,本地保存路径:{}", file.getAbsolutePath());
                    return true;
                }
            }
            ftpsClient.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ftpsClient.isConnected()) {
                try {
                    ftpsClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
}
public class FTPTest {
    public static void main(String[] args) {
        String host = "192.168.0.1";
        int port = 10021;
        String userName = "ftp01";
        String passWord = "ftp2022";
        
        FtpsUtils.login(host, port, userName, passWord);

        String directory = new SimpleDateFormat("yyyyMMddHH").format(new Date());
        File file = new File("/Users/Documents/Dockerfile");
        FtpsUtils.uploadFile(directory, file);

        FtpsUtils.login(host, port, userName, passWord);
        File uploadFilePath = new File("/Users/Desktop/ftpDemo/Dockerfile");
        FtpsUtils.downloadFile(directory, uploadFilePath);

    }

}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值