http://blog.csdn.net/wumenglu1018/article/details/54233826
FTP的主动传输和被动传输
主动模式:
- 客户端从端口N向服务器21端口发起连接.
- 客户端再N+1端口监听服务器的连接.
-
服务器从端口20 向客户端 N+1 端口发起连接.
image.png
被动模式:
- 客户端从端口N向服务器21端口发起连接.
- 服务端在X端口(X>1024)监听客户端的连接.
-
客户端从端口N+1 向服务端 X 端口发起连接.
image.png
主动FTP:
命令连接:客户端 大于1024
端口 -> 服务器 21
端口
数据连接:客户端 大于1024
端口 <- 服务器20
端口
被动FTP:
命令连接:客户端 大于1024
端口 -> 服务器 21
端口
数据连接:客户端 大于1024
端口 -> 服务器 大于1024
端口
简要总结:
- 主动FTP对FTP服务器的管理有利,但对客户端的管理不利。因为FTP服务器企图与客户端的高位随机端口建立连接,而这个端口很有可能被客户端的防火墙阻塞掉。
- 被动FTP对FTP客户端的管理有利,但对服务器端的管理不利。因为客户端要与服务器端建立两个连接,其中一个连到一个高位随机端口,而这个端口很有可能被服务器端的防火墙阻塞掉。
办法:
- 既然FTP服务器的管理员需要他们的服务器有最多的客户连接,那么必须得支持被动FTP。我们可以通过为FTP服务器指定一个有限的端口范围来减小服务器高位端口的暴露。这样,不在这个范围的任何端口会被服务器的防火墙阻塞。虽然这没有消除所有针对服务器的危险,但它大大减少了危险.
例:
Class FTPParam : FTP所需参数
import lombok.Builder;
/**
* ftp配置属性
*/
@Builder
public class FTPParam {
private String host;
private int port;
private String username;
private String password;
private String uploadPath;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUploadPath() {
return uploadPath;
}
public void setUploadPath(String uploadPath) {
this.uploadPath = uploadPath;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("FTPParam [host=");
builder.append(host);
builder.append(", port=");
builder.append(port);
builder.append(", username=");
builder.append(username);
builder.append(", password=");
builder.append(password);
builder.append(", uploadPath=");
builder.append(uploadPath);
builder.append("]");
return builder.toString();
}
}
Class FTPUtil: ftp工具类
public class FTPUtil {
public final static Logger LOG = LoggerFactory.getLogger(FTPUtil.class);
/**
* 发送文件到FTP
*
* @param fileLocalPath 本地文件路径(包含文件名 eg: //var//temp//test)
* @param fileName 远程服务器文件名
* @param param ftp配置
* @return
*/
public static boolean downLoadFileToLocal(String fileLocalPath, String fileName, FTPParam param) {
LOG.info("开始下载文件至本地,param:{}",param);
//状态
boolean result = false;
FTPClient ftpClient = new FTPClient();
FileOutputStream fout = null;
try {
ftpClient.connect(param.getHost(), param.getPort());
//判断ftp连接
if(!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
LOG.error("ftp connect fail,host:{}",param.getHost());
ftpClient.disconnect();
return result;
}
LOG.info("ftpClient.connect success.");
//判断ftp登陆
if(!ftpClient.login(param.getUsername(), param.getPassword())) {
LOG.error("ftp login fail,username:{}",param.getHost());
ftpClient.logout();
return result;
}
//设置文件类型 :二进制
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
//采用被动模式传输
ftpClient.enterLocalPassiveMode();
//设置路径
LOG.info("ftpClient.connect 设置路径:{}",param.getUploadPath());
boolean change = ftpClient.changeWorkingDirectory(param.getUploadPath());
if(change){
fout = new FileOutputStream(fileLocalPath);
result = ftpClient.retrieveFile(fileName, fout);
LOG.info("---FTP下载完成---");
}
else {
LOG.info("ftpClient.connect 设置路径失败:{}", param.getUploadPath());
}
} catch (Exception e) {
LOG.error("下载文件出错,报错:",e);
} finally {
try {
if(fout != null) {
fout.close();
}
if(ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
LOG.error("关闭FTP或字节流出错,报错:",e);
}
}
return result;
}
/**
* 发送文件到FTP
*
* @param fileLocalPath 本地文件路径(包含文件名 eg: //var//temp//test)
* @param fileName 文件名(上传到远程服务器的文件名)
* @param param ftp配置
* @return
*/
public static boolean upLoadFileToFTP(String fileLocalPath, String fileName, FTPParam param) {
LOG.info("开始发送文件至FTP,param:{}",param);
//状态
boolean fal = false;
FTPClient ftpClient = new FTPClient();
FileInputStream fis = null;
File file = null;
try {
ftpClient.connect(param.getHost(), param.getPort());
//判断ftp连接
if(!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
LOG.error("ftp connect fail,host:{}",param.getHost());
ftpClient.disconnect();
return fal;
}
LOG.info("ftpClient.connect success.");
//判断ftp登陆
if(!ftpClient.login(param.getUsername(), param.getPassword())) {
LOG.error("ftp login fail,username:{}",param.getHost());
ftpClient.logout();
return fal;
}
//设置文件类型 :二进制
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
file = new File(fileLocalPath);
fis = new FileInputStream(file);
//采用被动模式传输
ftpClient.enterLocalPassiveMode();
//设置上传路径
boolean change = ftpClient.changeWorkingDirectory(param.getUploadPath());
LOG.info("ftpClient.connect 设置上传路径:{}",param.getUploadPath());
if(change) {
fal = ftpClient.storeFile(fileName, fis);
LOG.info("---FTP上传完成---");
}else{
LOG.info("ftpClient.connect 设置上传路径失败:{}",param.getUploadPath());
}
} catch (Exception e) {
LOG.error("上传FTP出错,报错:",e);
} finally {
try {
if(fis != null) {
fis.close();
}
fis = null;
file = null;
if(ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
LOG.error("关闭FTP或字节流出错,报错:",e);
}
}
return fal;
}
网友评论