报错信息
ftp上传文件报org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication错误
项目中由于ftp做了迁移,代码使用的ftpclient登录成功,但是上传文件就报这个错误。
代码
public boolean uploadFile(String ip, int port, String username,
String password, String serverpath, String file) {
// 初始表示上传失败
boolean success = false;
// 创建FTPClient对象
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF-8");
ftp.setConnectTimeout(20000);
ftp.setDataTimeout(600000);
ftp.enterLocalPassiveMode();
ftp.setActivePortRange(4000, 4100);
try {
int reply=0;
// 连接FTP服务器
// 如果采用默认端口,可以使用ftp.connect(ip)的方式直接连接FTP服务器
ftp.connect(ip, port);
//ftp.connect("192.168.20.221", 21);
// 登录ftp
ftp.login(username, password);
// 看返回的值是不是reply>=200&&reply<300 如果是,表示登陆成功
reply = ftp.getReplyCode();
logger.info("连接ftp服务器响应码,reply={}",reply);
// 以2开头的返回值就会为真
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return success;
}
ftp.setActivePortRange(40000, 41000);
logger.info("ftp连接成功。。。file = {}, serverpath = {}", file, serverpath);
checkPathExist(ftp,iso8859ToGbk(serverpath));
//输入流
InputStream input=null;
try {
file=gbkToIso8859(file);
input = new FileInputStream(iso8859ToGbk(file));
} catch (Exception e) {
LoggerFactory.getLogger(this.getClass()).error("读取上传文件出错",e);
}
// 将上传文件存储到指定目录
file=iso8859ToGbk(file);
String fileName = getFilename(file);//8859
int index = fileName.lastIndexOf(".");
String tmpFileName = fileName.substring(0,index)+".tmp";
ftp.deleteFile(iso8859ToGbk(fileName));
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
String ftpPath = iso8859ToGbk(serverpath)+"/"+iso8859ToGbk(tmpFileName);
logger.info("上传前ftp路径,ftpPath = {}",ftpPath);
boolean flag = ftp.storeFile(ftpPath, input);
logger.info("上传文件后,上传结果flag = {}", flag);
// 关闭输入流
input.close();
if(flag){
ftp.rename(iso8859ToGbk(serverpath)+"/"+iso8859ToGbk(tmpFileName),
iso8859ToGbk(serverpath)+"/"+iso8859ToGbk(fileName));
success = true;
}
// 退出ftp
ftp.logout();
} catch (IOException e) {
success = false;
LoggerFactory.getLogger(this.getClass()).error("上传数据到ftp出错",e);
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
LoggerFactory.getLogger(this.getClass()).info(ioe.toString());
}
}
}
return success;
}
ftp主被动模式介绍
主动模式:FTP客户端向服务器的FTP控制端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路;当需要传送数据时,客户端在命令链路上用PORT的命令告诉服务器我开放了某端口,你过来连接我。于是服务器从20端口向客户端的该端口发送连接请求,建立一条数据链路来传送数据。在数据链路建立过程中是服务器主动请求,所以称为主动模式。
被动模式:FTP客户端向服务器的FTP控制端口(默认21)发送连接请求,服务器接受连接,建立一条命令链路;当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端,我打开了某端口,你过来连我。于是客户端向服务器的该端口发送连接请求,建立一条数据链路来传送数据。在数据链路建立的过程中是服务器被动等待客户机的请求,所以称被动模式。
原因分析
看我们上面的代码,就知道,在ftp登录成功后,执行了ftp.setActivePortRange(40000, 41000);,这个表示使用主动模式传输数据,主动模式需要ftp服务器连我们的端口,结果,由于网络问题,ftp服务器无法连接客户端的端口,所以就报了这个错误。
解决方案
对于这个问题,应该有两种解决方案:一、开通网络,是ftp服务器能够连接客户端40000~41000的端口;二、就是改成被动模式。
在这里我就采取了第二种方法:在ftp客户端登录成功后(在登录之前执行是无效的),执行ftp.enterLocalPassiveMode();就可以了,最终代码如下:
public boolean uploadFile(String ip, int port, String username,
String password, String serverpath, String file) {
// 初始表示上传失败
boolean success = false;
// 创建FTPClient对象
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF-8");
ftp.setConnectTimeout(20000);
ftp.setDataTimeout(600000);
ftp.enterLocalPassiveMode();
ftp.setActivePortRange(4000, 4100);
try {
int reply=0;
// 连接FTP服务器
// 如果采用默认端口,可以使用ftp.connect(ip)的方式直接连接FTP服务器
ftp.connect(ip, port);
//ftp.connect("192.168.20.221", 21);
// 登录ftp
ftp.login(username, password);
// 看返回的值是不是reply>=200&&reply<300 如果是,表示登陆成功
reply = ftp.getReplyCode();
logger.info("连接ftp服务器响应码,reply={}",reply);
// 以2开头的返回值就会为真
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return success;
}
ftp.enterLocalPassiveMode();// 这是改为被动模式
logger.info("ftp连接成功。。。file = {}, serverpath = {}", file, serverpath);
checkPathExist(ftp,iso8859ToGbk(serverpath));
//输入流
InputStream input=null;
try {
file=gbkToIso8859(file);
input = new FileInputStream(iso8859ToGbk(file));
} catch (Exception e) {
LoggerFactory.getLogger(this.getClass()).error("读取上传文件出错",e);
}
// 将上传文件存储到指定目录
file=iso8859ToGbk(file);
String fileName = getFilename(file);//8859
int index = fileName.lastIndexOf(".");
String tmpFileName = fileName.substring(0,index)+".tmp";
ftp.deleteFile(iso8859ToGbk(fileName));
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
String ftpPath = iso8859ToGbk(serverpath)+"/"+iso8859ToGbk(tmpFileName);
logger.info("上传前ftp路径,ftpPath = {}",ftpPath);
boolean flag = ftp.storeFile(ftpPath, input);
logger.info("上传文件后,上传结果flag = {}", flag);
// 关闭输入流
input.close();
if(flag){
ftp.rename(iso8859ToGbk(serverpath)+"/"+iso8859ToGbk(tmpFileName),
iso8859ToGbk(serverpath)+"/"+iso8859ToGbk(fileName));
success = true;
}
// 退出ftp
ftp.logout();
} catch (IOException e) {
success = false;
LoggerFactory.getLogger(this.getClass()).error("上传数据到ftp出错",e);
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
LoggerFactory.getLogger(this.getClass()).info(ioe.toString());
}
}
}
return success;
}
期望对大家有所帮助。