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

Posted 蓝风9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了07 来自于网友的 retrieveFileStream 的一个问题, 导致系统程序异常相关的知识,希望对你有一定的参考价值。

前言

可以先参考前面一篇文章 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 次, 随机碰撞端口 

完 

以上是关于07 来自于网友的 retrieveFileStream 的一个问题, 导致系统程序异常的主要内容,如果未能解决你的问题,请参考以下文章

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

来自部分网友的FPGA面试经验~~

物理学家用相对论破解意识之谜引热议,网友直呼看不明白,作者:意识不完全来自大脑...

Chrome VS IE--国产系统“强行”快于国外系统,网友:面对现实这么难?

回答一网友的问题:又是一次二层环路引起的网络震荡

热烈庆祝老男孩运维28期脱产班爆满开班及答谢51CTO网友