Ftp下载文件超时处理

2022-06-21 00:00:00 文件 超时 下载

问题描述:

使用apache 开源库:commons-net 里的ftp进行文件下载,下载过程中发现由于网络拥挤或者是文件太大导致程序假死,不继续执行(实际上文件下载成功)

问题查找:
1、测试下载小文件没有问题
《Ftp下载文件超时处理》
2、直接使用ftp命令下载(文件下载正常,但是没接收到返回码226)
《Ftp下载文件超时处理》
3、文件实际下载成功(使用md5sum 校验文件是正常无损坏)

4、查看ftp服务器日志(vsftp.log)自己的服务器,如果是外部提供是无法查询的
《Ftp下载文件超时处理》
ftp服务器端有正常返回,只是客户端没接收到

原因:

  • FTPClient.listFiles()或者FTPClient.retrieveFile()方法时,就停止在那里,什么反应都没有,出现假死状态
  • 连接FTP服务器,长时间进行数据操作时,超时自动断开

listFiles函数没反应可以下面方法(被动模式),这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据

	ftpClient.enterLocalPassiveMode();//不加这个无法加载文件列表

客户端断开连接添加keepAlive函数保持连接

	ftpClient.login(username, password);
	ftpClient.setControlKeepAliveTimeout(30);//用于设置传输控制命令的 Socket 的 alive 状态,注意单位为 s。
	ftpClient.setControlKeepAliveReplyTimeout(3000);

retrieveFile()函数源码分析:

    public boolean retrieveFile(String remote, OutputStream local)
    throws IOException
    { 
        InputStream input;
        Socket socket;

        if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null)
            return false;

        input = new BufferedInputStream(socket.getInputStream(),
                getBufferSize());
        if (__fileType == ASCII_FILE_TYPE)
            input = new FromNetASCIIInputStream(input);

        CSL csl = null;
        //使用setControlKeepAliveTimeout函数就是作用于这块,保持客户端和服务器的连接
        if (__controlKeepAliveTimeout > 0) { 
            csl = new CSL(this, __controlKeepAliveTimeout, __controlKeepAliveReplyTimeout);
        }

        // Treat everything else as binary for now
        try
        { 
            Util.copyStream(input, local, getBufferSize(),
                    CopyStreamEvent.UNKNOWN_STREAM_SIZE, __mergeListeners(csl),
                    false);
        } finally { 
            Util.closeQuietly(socket);
        }

        // Get the transfer response
        boolean ok = completePendingCommand();
        if (csl != null) { 
            csl.cleanUp(); // fetch any outstanding keepalive replies
        }
        return ok;
    }

通过上述函数的添加解决大文件下载超时没正常返回226出现的假死情况

完整的连接ftp代码:

public static FTPClient createFTPClient(String ip, Integer port, String username, String password, String workDir)
        throws SocketException, IOException { 
    FTPClient ftpClient = new FTPClient();

	ftpClient.setDefaultTimeout(30 * 60 * 1000);
	ftpClient.setConnectTimeout(30 * 60 * 1000);
	ftpClient.setDataTimeout(30 * 60 * 1000);

	ftpClient.connect(ip, port == null ? 21 : port);
	// socket连接,设置socket连接超时时间(单位:ms)
	ftpClient.setSoTimeout(30 * 60 * 1000);
	
	ftpClient.enterLocalPassiveMode();//不加这个无法加载文件列表
	ftpClient.login(username, password);
	ftpClient.setControlKeepAliveTimeout(30);//用于设置传输控制命令的 Socket 的 alive 状态,注意单位为 s。
	ftpClient.setControlKeepAliveReplyTimeout(3000);

	ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    int reply = ftpClient.getReplyCode();
    if (!FTPReply.isPositiveCompletion(reply)) { 
        ftpClient.disconnect(); // 如果返回状态不再 200 ~ 300 则认为连接失败
        throw new RuntimeException("FTP链接失败");
    }
    if (workDir != null && !"".equals(workDir)) { 
        ftpClient.changeWorkingDirectory(workDir);
    }
    return ftpClient;
}

更多参数设置参考地址:https://www.cnblogs.com/dasusu/p/10006899.html

    原文作者:zhuzi121121
    原文地址: https://blog.csdn.net/zhuzi121121/article/details/111881277
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章