要实现文件上传功能。为了模拟正式环境的文件上传,我在本地搭建了FTP服务器,将功能实现。在正式环境下,由于本地的FTP和正式环境下的FTP有出入,上线时出现了问题。本篇文章记录使用FTP被动模式,从FTP搭建一直到功能上线在FTP上出现的诸多问题。

  这篇文章能解决的问题如下:

1、什么是被动模式和主动模式;

2、java操作上传至FTP过程中出现的阻塞异常;java FTP在执行uploadfile时卡住了;
3、java获取FTP目录列表出现的阻塞异常;

4、用户被锁定到各自目录为其根目录;或,java连接FTP后,如何正确使用changeWorkingDirectory()如何定位路径;或,java连接FTP后,执行changeWorkingDirectory()后,定位到了Linux根目录而非FTP用户的根目录的问题。

5、cmd中可以连接FTP,但无法执行ls命令报出425错误,linux下却可以连接并执行ls。

什么是主动模式和主动模式。

      FTP通过TCP协议进行连接,一般情况下服务器上开放21号端口作为命令端口,20号端口作为数据端口。顾名思义,两个端口分别负责命令的传递,和数据的传递。当服务器发送命令,如“ftp > bye”就是通过21端口;如果要上传或者下载的时候,就要通过数据端口传输数据。

   主动模式下端口之间的通讯

   主动模式下,FTP客户端从任意的非特殊的端口(N > 1023)连入到FTP服务器的命令端口--21端口。然后客户端在N+1(N+1 >= 1024)端口监听,并且通过N+1(N+1 >= 1024)端口发送命令给FTP服务器。服务器会反过来连接用户本地指定的数据端口。

 

java 连接ftp 域名 java连接ftp被拒绝_服务器

(程序之外的往事 ,是我的微信公众号,我转我自己)

 

   被动模式下端口之间的通讯(这段引用了一位网友的文章,理解的还不错)

   在被动方式FTP中,命令连接和数据连接都由客户端,这样就可以解决从服务器到客户端的数据端口的入方向连接被防火墙过滤掉的问题。当开启一个FTP连接时,客户端打开两个任意的非特权本地端口(N >; 1024和N+1)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交PASV命令。这样做的结果是服务器会开启一个任意的非特权端口(P >; 1024),并发送PORT P命令给客户端。然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。

java 连接ftp 域名 java连接ftp被拒绝_java_02

   与主动模式相比,被动模式下,在服务器端需要开启高位端口来负责数据的传递。在FTP配置文件vsftp.conf中,可以看到配置了被动模式下数据端口的开放区间

pasv_min_port=8080

pasv_max_port=9080

pasv_enable=YES

所以,服务器的防火墙要设置允许暴露出这些端口,客户端才能与这些端口相连。

 

解决第2、3问题

   在java操作FTP时,常常会出现上传至FTP过程中出现的阻塞异常和获取FTP目录列表出现的阻塞异常。测试环境下会间歇性的有这种情况,在正式环境下,这种现象尤甚。从搜索了资料后,要在每次上传之前和获取目录之前,添加ftp.enterLocalPassiveMode();这个方法的目的是为了,告诉程序我们在使用被动模式,每次有数据的交流之前,服务器端新开一个端口负责数据的传输。不要只在连接FTP的时候设置一次,要每次上传和获取目录列表都设置。

 

解决问题4

  在本地时,登录后进入的是FTP用户根目录下,用pwd命令获取的路径是“/”,而在正式环境中,用户登上FTP主机不会进入FTP用户的根目录“/”路径,而是进入运维分配好的FTP用户根目录下的某个路径,用pwd就是“/XXXX/XXXX/XXX”路径。所以在java执行FTP切换目录方法的时候,要注意携带pwd显示的路径为前缀,后面才是你要cd到的目标目录。否则java FTP会从”/”目录下开始寻找。必然在正式环境下找不到你要cd的目录。 

   找到了让我的测试环境和正式环境统一的方法,需要将这一条(#chroot_local_user=YES)注释掉,或者改成NO。自此,正式环境和测试环境的pwd的输出都是 /XXXX/XXXX/XXX的格式了。

         但为了让java程序应对这两种情况,并使java程序更健壮。在cd到你想要的FTP目录前,首先要 ftp.printWorkingDirectory()获取登录后的工作目录,先cd到工作目录再cd到你的目标目录。

 

解决问题5

 

    cmd中可以连接FTP,但无法执行ls命令报出425错误,linux下可以。

网上很多解决方案,可惜都解决不了问题,不能说他们不对,而是引起这种现象的原因有不同。我根据以往的经验,自己解决了这种问题。在网上的解决方案中,一般指向服务器。但这个是客户端的问题。大家可以在控制面板中,找到防火墙高级设置

 

java 连接ftp 域名 java连接ftp被拒绝_java_03

 

然后找到“入站规则”中的“文件传送程序”允许就可以了。为什么只开放了协议是TCP的,没有开放UDP的。因为FTP传输是用的TCP协议。

java 连接ftp 域名 java连接ftp被拒绝_java 连接ftp 域名_04

 

出站就是你访问外网,入站就是外网访问你。在FTP交互中,FTP服务器也是要向客户端发请求的,由于客户端的入站规则禁止了,所以接受不了。