转载请注明出处:原博文传送门
1. 问题
使用 commons.net 包下载小文件时程序能够顺利完成,但在下载大文件时程序会将文件下载完毕(检查文件大小,跟需要下载的文件大小一直),但是一直卡在 FTPClient.retrieveFile 方法。在网上查找了很多原因,大概了解了问题的所在。
多大算大文件? 跟你的网速和服务器的网速有关系,其实不是大小问题,是跟数据传输时间有关系,具体原因请看下面。
2. 原因
FTPClient 连接时会产生两个 socket 连接,一个用来传输命令,一个用来传输数据。
当我们在上传和下载大文件时,只有传输数据的socket连接在活动,那么传输命令的socket长时间没有命令,就会被关闭,当我们文件下载或上传完毕后,FTPClient 调用 命令socket 就会一直等待,造成了上面说的问题。
3. 解决办法
- 设置 FTPClient 每隔多少秒发送一次心跳信息
ftpClient.setControlKeepAliveTimeout(60); // 60s发送一次
/**
* Set the time to wait between sending control connection keepalive messages
* when processing file upload or download.
*
* @param controlIdle the wait (in secs) between keepalive messages. Zero (or less) disables.
* @since 3.0
* @see #setControlKeepAliveReplyTimeout(int)
*/
public void setControlKeepAliveTimeout(long controlIdle){
__controlKeepAliveTimeout = controlIdle * 1000;
}
我的配置信息
FTPClient ftpClient = new FTPClient();
ftpClient.setDefaultTimeout(3000);//设置默认超时时间
ftpClient.setConnectTimeout(3000);//设置连接超时时间
ftpClient.setDataTimeout(3000);//设置读取数据超时时间(每次socket传输,不是指整个下载)
ftpClient.setControlKeepAliveTimeout(60); // 设置ftp在上传或下载大文件时,保持ftp的control的socket连接keepalive
ftpClient.setControlEncoding("utf-8");//设置ftp字符集
ftpClient.enterLocalPassiveMode();//设置被动模式,文件传输端口设置