07 来自于网友的 retrieveFileStream 的一个问题, 导致系统程序异常

news2024/12/29 12:56:01

前言

可以先参考前面一篇文章 retrieveFileStream 之后需要调用 completePendingCommand 否则业务代码会存在问题 retrieveFileStream 之后需要调用 completePendingCommand 否则业务代码会存在问题

这里的问题 主要是来自于 某 qq 交流群的网友

呵呵 当然 这里测试用例代码的问题也是 非常多, 我们这里 只关注于 造成业务异常的相关部分 

测试用例

/**
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2022-09-16 15:22
 */
public class Test20MultiThreadDownloadFile implements Runnable {

    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            new Thread(new Test20MultiThreadDownloadFile()).start();
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    public void run() {
        while (true) {
            try {
                syncFile();

            } catch (Exception e) {
                System.err.println(ExceptionUtils.getFullStackTrace(e));
            } finally {
                try {
                    Thread.sleep(1000 * 60 * 1);
                } catch (InterruptedException e) {
                    System.err.println(ExceptionUtils.getFullStackTrace(e));
                }
            }

        }

    }

    public void syncFile() {
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient.connect("localhost", 21);
            if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                if (ftpClient.login("root", "root")) {
                    System.out.println("FTP连接成功");
                }
            }

            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileTransferMode(FTP.BINARY_FILE_TYPE);

            ftpClient.changeWorkingDirectory("/");
            FTPFile[] files = ftpClient.listFiles();

            for (FTPFile ftpFile : files) {
                boolean isPending = false;
                try {
                    //if(StringUtils.equals(DateUtil.formatDate(new Date(), "yyyyMMdd"), ftpFile.getName().substring(28,36))){
                    System.out.println(Thread.currentThread().getName() + "|" + ftpFile.getName() + "开始同步");
                    InputStream input = ftpClient.retrieveFileStream(ftpFile.getName());
//                    isPending = (input != null);
                    //File localFile = new File(ComUtils.getAttachFilePathPrefix()+SysConts.GROUPBILL_ATTA_PATH+ftpFile.getName());
                    File localFile = new File("/Users/jerry/Tmp/Test20MultiThreadDownloadFile/" + ftpFile.getName());
                    localFile.getParentFile().mkdirs();
                    if (!localFile.exists()) {
                        localFile.createNewFile();
                    }
                    if (localFile.length() > 10) {
                        System.out.println(Thread.currentThread().getName() + "|文件已同步,跳过" + ftpFile.getName());
                        continue;
                    }
                    if (!localFile.canWrite()) {
                        System.out.println(Thread.currentThread().getName() + "|文件不能操作,跳过" + ftpFile.getName());
                        continue;
                    }

                    FileOutputStream out = new FileOutputStream(localFile);
                    byte[] buffer = new byte[1024];
                    int read;
                    while ((read = input.read(buffer, 0, buffer.length)) != -1) {
                        out.write(buffer, 0, read);
                    }
                    out.flush();
                    out.close();
                    input.close();
                    isPending = true;
                    System.out.println(Thread.currentThread().getName() + "|文件同步完成," + ftpFile.getName());
                    //}
                } catch (Exception e) {
                    System.err.println(ExceptionUtils.getFullStackTrace(e));
                } finally {
                    if (isPending) {
                        ftpClient.completePendingCommand();
                        System.out.println(Thread.currentThread().getName() + "发起结束命令");
                    }
                }
            }

        } catch (Exception e) {
            System.err.println(ExceptionUtils.getFullStackTrace(e));
        } finally {
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.disconnect();
                    System.out.println("FTP退出成功");
                }
            } catch (IOException e) {
                System.err.println(ExceptionUtils.getFullStackTrace(e));
            }
        }
    }

}

相关问题剖析

这里会出现 几种导致问题的情况, 主要的问题是 retrieveFileStream 之后未消费 retrieveFileStream 的第二次响应 

1. ”if (localFile.length() > 10) {“ 中判断了目标文件是否已经存在, 如果存在 则跳过, isPending 为 false, 这里是可能 未消费 retrieveFileStream 的第二次响应的

2. ”if (!localFile.canWrite()) {“ 中判断了目标文件是否可以操作, 如果不可写 则跳过, isPending 为 false, 这里是可能 未消费 retrieveFileStream 的第二次响应的

3. “while ((read = input.read(buffer, 0, buffer.length)) != -1) {” 中 input 时可能为 null, 的因为 pasv 请求可能重试了 10 次之后绑定数据端口不成功, 然后 input 就是 null, 之后走的 catch, finally, isPending 为 false, 这里是可能 未消费 pasv 的响应异常的 

如下图是 场景三 的响应 

问题的处理方式

将 isPending 调整为如下即可 

对于 "500 OOPS: vsf_sysutil_bind" 因为重试次数是代码里面固定死的 

因此 要么调整被动模式的端口数量, 要么调整 客户端线程数量, 降低冲突的概率 

被动模式 vsftpd 开放数据端口

重试 10 次, 随机碰撞端口 

完 

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

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

相关文章

新鲜速递:Spring Data JPA 3.0快速入门、进阶到精通

第一章、安装Spring Data JPA 第一步&#xff0c;先确保你使用的是Spring Boot 3.0或以上环境&#xff0c;可以在pom.xml里加入Spring Data JPA依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-…

【ROS】—— ROS通信机制——话题通信(二)

文章目录前言1. 话题通信1.1 话题通讯理论模型1.2 话题通信基本操作&#xff08;C&#xff09;1.2.1 简单发布框架的实现1.2.2 发布逻辑的实现1.2.3 订阅方的实现1.3 话题通信基本操作&#xff08;python&#xff09;1.3.1 发布的实现1.3.2 订阅的实现1.4 话题通信自定义msg1.4…

五问补盲(五)| 想要长得好看又好用,补盲激光雷达应该怎么做?

上期&#xff0c;我们聊了好用的补盲激光雷达&#xff0c;得满足哪些条件&#xff1f; 好用是必备素质&#xff0c;属于补盲激光雷达的底线。好用之外&#xff0c;补盲激光雷达还有一种更直观的竞争力&#xff0c;那就是——外型。 有句话说的好&#xff0c;很多时候&#xff0…

2022跟学尚硅谷Maven入门(二)IDEA操作

2022跟学尚硅谷Maven入门二 IDEA操作第四章 使用Maven&#xff1a;IDEA环境第一节 创建父工程1.创建 Project2.开启自动导入第二节 配置 Maven 信息第三节 创建 Java 模块工程第四节 创建Web模块工程1.创建模块2.修改打包方式3.Web 设定4.借助IDEA生成web.xml5.设置 Web 资源的…

数据库,计算机网络、操作系统刷题笔记21

数据库&#xff0c;计算机网络、操作系统刷题笔记21 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

基于thinkphp6搭建的 admin后台管理基础框架,方便快速进行二次开发

小牛Admin v2.1 完整代码下载地址&#xff1a;基于thinkphp6搭建的 admin后台管理基础框架 使用thinkphp6 layui 搭建的 admin后台管理基础框架&#xff0c;方便快速进行二次开发 该项目是在 http://www.xnadmin.cn/ 小牛Admin 开源项目的基础上进行个人优化的产物 运行环境…

Redis-用户签到UV统计

一、用户签到 1.1 BitMap用法 我们按月来统计用户签到信息&#xff0c;签到记录为1,未签到记录为0 把每一个bit位对应当月的每一天&#xff0c;形成了映射关系。用0和1表示业务状态&#xff0c;这种思路就称为位。Redis中是用利用string类型数据结构实现BitMap&#xff0c;因…

使用pip命令时,报错:_sysconfigdata_x86_64_conda_cos7_linux_gnu.py

问题&#xff1a; 在linux服务器中想使用pip命令pip show list查看安装了哪些包时&#xff0c;报错 ModuleNotFoundError: No module named ‘_sysconfigdata_x86_64_conda_cos7_linux_gnu’ 问题原因 原因是&#xff1a;在当前的环境下的python中丢失了一个备份文件&#xf…

经典算法之常用排序

目录❤️前言&#x1f498;一、分治思想&#x1f49e;二、归并排序1.实现方法2.动图分析3.代码模板&#x1f496;三、快速排序1.实现方法2.动图分析3.代码模板❤️前言 本文介绍两种基于分治思想的经典排序算法&#xff1a; 归并排序与快速排序 &#x1f498;一、分治思想 分…

【Python从入门到进阶】1、初识Python

一、Python的起源 1989年&#xff0c;为了打发圣诞节假期&#xff0c;荷兰程序员Gudio van Rossum吉多●范罗苏姆(龟叔&#xff0c;下图穿“人生苦短&#xff0c;我用Python”T恤衫的老哥)决心开发一个新的解释程序&#xff08;Python维形&#xff09;; 1991年&#xff0c;第一…

机器学习中的数学原理——向量内积

今天是2023年的第一天&#xff0c;祝大家新年快乐&#xff01;这个专栏主要是用来分享一下我在机器学习中的学习笔记及一些感悟&#xff0c;也希望对你的学习有帮助哦&#xff01;感兴趣的小伙伴欢迎私信或者评论区留言&#xff01;这一篇就更新一下《白话机器学习中的数学——…

【C语言】指针

文章目录指针作为参数的指针访问某个地址上的变量*指针的应用数组和指针数组变量是特殊的指针指针常量和常量指针数组指针和指针数组常见错误指针运算动态内存分配指针 一般用p来表示一个指针&#xff0c;来自pointer 一个指针类型的变量就是保存地址的变量。 变量的值是内存…

windows x32调用门实现 ring3提权

概述 调用门是Intel提供的一个机制&#xff0c;用于控制不同权限级(ring0-ring3)的程序函数调用。简单点就是提供了一个ring3 调用ring0 函数的机制。 在intel手册volume3-Chapter 5.83描述如下 Call gates facilitate controlled transfers of program control between dif…

算法笔记(25)win10系统安装tensorflow-GPU环境亲测好用

环境准备 首先你的电脑得有GPU显卡&#xff0c;然后在tensorflow官网&#xff08;在 Windows 环境中从源代码构建 | TensorFlow&#xff09;找到各安装软件对应的版本&#xff0c;版本不对应将会导致安装失败。 标本机GPU显卡版本题本文选择的是官网最新的组合&#xff1a;p…

cubeIDE开发, stm32窗口看门狗WWDG的CubeMX配置及HAL库底层实现分析

一、stm32的WWDG说明 1.1 WWDG特点&#xff1a; 在前一篇博文介绍独立看门狗时就指出STM32 MCU提供两个看门狗&#xff0c;独立看门狗和窗口看门狗。 cubeIDE开发&#xff0c; stm32独立看门狗IWDT的CubeMX配置及HAL库底层实现分析_py_free的博客-CSDN博客 相比独立看门狗&am…

【C语言】数据类型

文章目录c语言的类型整数整数类型整数的内部表达整数的范围unsigned整数的格式化浮点型浮点类型输入输出输出精度字符类型逃逸字符类型转换自动类型转换强制类型转换逻辑类型bool逻辑运算条件运算符C语言的变量&#xff0c;必须在使用前定义&#xff0c;并且确定类型&#xff1…

ubuntu下使用doxygen生成软件文档

ubuntu下使用Doxygen生成软件文档一、软件下载1.系统安装Doxygen2.Vscode插件安装二、软件配置三、文档生成1.方法1&#xff1a;使用Doxygen-gui生成&#xff08;推荐&#xff09;2.方法&#xff1a;采用Doxygen命令&#xff08;不推荐&#xff09;另外Windows下使用方法提示&a…

【JavaScript】 Date 日期对象概述及相关方法

文章目录【JavaScript】 Date 日期对象的创建及相关方法一. 日期对象的创建二. 日期对象的相关方法三. 时间戳案例案例1&#xff1a;在页面上展示一个时钟&#xff0c;隔1s更新一次案例2&#xff1a;距离除夕倒计时【JavaScript】 Date 日期对象的创建及相关方法 一. 日期对象…

ArcGIS基础:构建点对连线表达点集内部相互关系

原始数据如下&#xff0c;为普通的点图层&#xff0c;总共是21个点。 点位分布如下&#xff1a; 属性表打开如下&#xff1a; 下面使用【构造视线】工具进行操作&#xff0c;其工具位于【3D分析工具】下的【可见性】工具栏。 打开【构造视线】对话框&#xff0c;把【视点…

Leetcode【494. 目标和】

题目描述 给你一个整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 ‘’ 或 ‘-’ &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 ‘’ &#xff0c;在 1 之前添加 ‘-’ &…