关于FTP文件传输的一些总结

最近项目上有个功能需求,就是要求在数据采集结束后,自动完成在设备间的数据传输。所以就想到了专门用来做数据传输的FTP,很简单的一个东西~
但是,网上对于主被动模式的具体使用场景介绍的大部分都很有问题,只是一味地说用被动模式,浪费了很多时间,所以在这里总结一下…

FTP基本介绍

FTP(file transfer protocol),用于在网络上进行文件传输的一套协议,可以实现访问远程资源,实现往返传输数据、目录管理等,即使是不同的操作系统和文件存储方式
all in all,简单易上手,优点多多~

传输特点

FTP是基于C/S模型(client/server)而设计的,在客户端和服务端之间建立了两个TCP连接,一个是控制连接,一个是数据连接。
你可以简单理解成两国外交会谈,控制连接就是两个外交部长在那里握手,表示我们开始会谈了,数据连接则是他们手下的小兵,负责具体会谈的内容~

FTP两种传输模式

FTP有两种传输协议,一种是主动模式,又称PORT模式;一种是被动模式,又称PASV模式。
不管是哪种,它们的控制连接(外交部长)都是服务器监听21端口,客户端找服务器的21端口发起TCP连接。
如何区分这两种模式就在于服务端对于客户端的访问是主动还是被动

  • 如果服务器去找客户端,那就是主动模式
  • 如果客户端来找服务器,那就是被动模式
    在主动模式里,服务器会把自己的20端口作为源端口,主动向客户端发起TCP数据连接;
    但在被动模式里,服务器随机开放端口,同控制连接告诉客户端,再由客户端来向服务器的这个端口发起TCP数据连接。

这两种模式的使用场景

主要根据从两个方面来考虑,设备和网络。(这一部分带有总结性质,可能会不准确)
去百度一搜 两种模式的使用场景,清一色的都是说要设置被动模式,但没有介绍为什么,不知所以然的跟着去做往往就是翻车。

需要注意的点

客户端和服务器端设置的时候一定要保持一致
不要一个设置成主动,一个设置成被动,这样必出问题。但很多时候你还不知道哪出了问题
简单的一句话,蕴含多少辛酸

软件推荐

服务器端

Wing FTP Server,一款专业的跨平台FTP服务器软件。有交互界面,方便管理和理解。一个月试用之后会变为免费版,很多功能用不了了,但是对于正常的使用没有影响。推荐!

其实很多专业的功能都还没有解锁使用过,但就现在的感觉来说这款很好用易懂。

客户端

FTP Rush,一款很小(3~4M)很好用的免费客户端软件,适用于Windows/Linux/Mac/Android/iOS等操作系统。
主要特性:

  • 纯净的免费软件, 而且易于使用, 解压zip安装包就能运行
  • 支持多种文件传输协议 - FTP, FTPS, SFTP, WebDAV, WingFTP Web Client (最新版的Rush 3,加入了对于云存储管理器的支持 (Google Drive, DropBox, OneDrive, Amazon S3))
  • 通过自定义的C#脚本您还可以轻松地制作自动化任务
  • 类似资源管理器的简单易用的界面并支持文件拖放

FTP代码实例

连接FTP服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* @paramhost     ftp服务器域名
* @paramusername 访问用户名
* @parampassword 访问密码
* @paramport 端口
* @return 是否连接成功
*/
public boolean ftpConnect(String host, String username, String password, int port){
try{
ftpClient = new FTPClient();
Log.i(TAG, "connecting to the ftp server " + host + ":" + port);
ftpClient.setConnectTimeout(5000);
ftpClient.connect(host, port);
//根据返回的状态码,判断链接是否建立成功
if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){
Log.i(TAG, "成功连接至ftp服务器");
boolean status = ftpClient.login(username, password);
/*
* 设置文件传输模式
* 使用BINARY_FILE_TYPE来传输文本、图像和压缩文件
*/
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//我的应用场景决定了我使用被动模式:PASV
ftpClient.enterLocalPassiveMode();
return status;
} else {
Log.i(TAG, "ftpConnect: 建立连接不成功");
ftpClient.disconnect();
}
} catch (Exception e){
Log.e(TAG, "could not connect to host: "+ e.toString());
e.printStackTrace();
}
}

断开FTP服务器连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* 断开ftp服务器连接
* 返回:断开结果
*/
public boolean ftpDisconnect(){
// 排除空指针
if (ftpClient == null){
return true;
}
// 断开ftp服务器连接
try{
if (ftpClient.isConnected()) {
ftpClient.logout();
} else {
Log.i(TAG, "ftpDisconnect:与FTP服务器本来就没有连接");
}
} catch (Exception e){
Log.i(TAG, "ftpClient.logout()时发生错误"+e.toString());
} finally {
try {
//注意,要将disconnect()放在finally模块里,因为logout也会抛出异常
ftpClient.disconnect();
Log.i(TAG, "ftpDisconnect:断开与FTP服务器的连接成功");
return true;
} catch (IOException e){
Log.i(TAG, "ftpClient.disconnect()时发生错误"+e.toString());
}
}
return false;
}

上传文件到FTP服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*上传文件到ftp
* ftpFileName 上传到ftp文件路径名称
* localFile 本地文件路径名称
*/
public void upload(String ftpFileName, File localFile) throws IOException{
if (!localFile.exists()){
throw new IOException("Can't upload '" + localFile.getAbsolutePath() + "'. This file doesn't exist.");
}
InputStream in = null;
try {
FileInputStream inputStream = new FileInputStream(localFile);
in = new BufferedInputStream(inputStream);

ftpClient.storeFile(ftpFileName,in);
} finally {
in.close();
}
}

以上是三个最基本的FTP使用方法…

参考资料