Ftp下载文件超时处理

问题描述:

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

问题查找:
1、测试下载小文件没有问题
在这里插入图片描述
2、直接使用ftp命令下载(文件下载正常,但是没接收到返回码226)
在这里插入图片描述
3、文件实际下载成功(使用md5sum 校验文件是正常无损坏)

4、查看ftp服务器日志(vsftp.log)自己的服务器,如果是外部提供是无法查询的
在这里插入图片描述
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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值