今天项目中要下载快钱的对账单,快钱对账单文件的FTP服务器是Unix系统,connectServer方法中已连接成功,reply code:220。

但是问题是download方法中的ftpClient.listFiles(remote)不能找到具体某一文件,如果使用ftpClient.listFiles()而不具体指定某一远程文件时可以列举出所有的文件,包括remote这个需要下载的文件。且代码中的ftpClient.retrieveFile(remote, out);会出现长时间的等待,upNewStatus为false,最终会抛出:FTP response 421 received.  Server closed connection.

 public static boolean connectServer(String host, int port, String user, String password, String defaultPath)
throws SocketException, IOException {
ftpClient = new FTPClient();
// org.apache.commons.net.MalformedServerReplyException: Could not parse response code.
// Server Reply: SSH-2.0-OpenSSH_7.2
// ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
// 设置以二进制方式传输
ftpClient.setDataTimeout(5000);
ftpClient.setConnectTimeout(connectTimeout);
ftpClient.setControlEncoding("UTF-8");
ftpClient.connect(host, port);
log.info("Connected to " + host + ".");
log.info("FTP server reply code:" + ftpClient.getReplyCode());
if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
if (ftpClient.login(user, password)) {
// Path is the sub-path of the FTP path
if (defaultPath != null && defaultPath.length() != 0) {
ftpClient.changeWorkingDirectory(defaultPath);
}
return true;
}
}
disconnect();
return false;
} public static File download(String remote, String local) throws IOException {
log.info("remote={},local={}", remote, local);
File downloadFile = null;
// 检查远程文件是否存在
FTPFile[] files = ftpClient.listFiles(remote);
if (files.length == 0) {
log.info("远程文件不存在: {}, {}", remote, files);
return downloadFile;
} File f = new File(local);
OutputStream out = null;
if (f.exists()) {
f.delete();
}
try {
//ftpClient.enterLocalPassiveMode();
out = new FileOutputStream(f);
boolean upNewStatus = ftpClient.retrieveFile(remote, out);
out.flush(); if (upNewStatus) {
downloadFile = f;
}
}
catch (Exception e) {
log.error(e.getMessage(), e);
}
finally {
if (out != null) {
out.close();
}
}
return downloadFile;
}

FTP需要在自己测试服务器开通21端口,这个已经叫运维开通了。且需要快钱把我们这边测试服务器ip加入快钱的白名单,否则是链接不到那边的FTP服务器的。

开始一直以为是快钱那边提供的用户是否需要什么文件连接权限,定位了很久的问题,最后搜索问题才发现对FTP连接模式和原理不清楚导致。

首先FTP分2中模式:主动模式(port)和被动模式(pasv).FTP标准命令TCP端口号为21,Port方式数据端口为20

不管哪种模式,都必须通过21这个端口建立起到FTP的管道连接,通过这个通道发送命令。

port模式:1.通过tcp的21端口建立起通道

     2.客户端在此通道发起PORT命令,并产生一个随机非特殊的端口号N(1023<N<65536)给到FTP服务器。

     3.此时客户端监听N+1端口(N+1>=1025,不一定是N端口+1),同时通过21的通道发送命令通知FTP服务器客户点通过此端口接受数据传输。

     4.FTP服务器接收到上一步的响应后通过自己的数据源端口20,去链接远程的客户端的N+1端口(此时是FTP服务端主动发起的一个端口链接)

     5.如果此时客户端的防火墙策略是不能随意外部链接内部服务器的端口,则会造成上一步出现数据端链接失败!

      6.如果没有上一步的情况,FTP客户端则会接收到服务端响应并返回响应信息,则建立起了数据链接通道。

pasv模式:1.通过tcp的21端口建立起通道

        2.但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交 PASV命令.会产生两个随机非特殊的端口N(1023<N<65536)                   和N+1给到FTP服务器。其中N端口跟主动模式一样,会把N给到服务端的远程的21端口。相当于FTP服务端被动接受数据端口号而不是之前port模式的主动发起连接

      3.FTP服务端会则会打开N+1的端口号

      4.客户端发起N+1端口的链接,并建立数据链接。

port模式:                          

pasv模式: 

上面的图都省略了建立tcp的21端口这个步骤。

正是因为之前采用主动模式,但是测试服务器防火墙阻止了快钱发起的数据端口的连接。也就是port模式的第5步出现问题。

因而FTPClient.listFiles(remote)或者FTPClient.retrieveFile(remote)方法时获取不了数据,就停止在那里,什么反应都没有,出现假死状态。

解决办法:在调用这两个方法之前,调用FTPClient.enterLocalPassiveMode();

这个方法的意思就是每次数据连接之前,ftp client告诉ftp server:数据连接的端口号已经告诉你了,你只需被动接受数据连接的请求就行

参考:http://www.cnblogs.com/xiaohh/p/4789813.html

    http://blog.csdn.net/u010154760/article/details/45458219

FTP下载时连接正常获取不到数据的更多相关文章

  1. ftp 下载时防止从缓存中获取文件

    //http://baike.baidu.com/link?url=QucJiA_Fg_-rJI9D4G4Z4687HG4CfhtmBUd5TlXrcWCeIEXCZxIh0TD7ng1wROAzAu ...

  2. RubyGem 下载时连接失败的解决方法

    RubyGem 下载 gem 包失败,有一定原因是 https 导致的. 搜索了很久,找到一个解决的方法. 1.下载 cacert.pem,也就是 curl 的证书. http://curl.haxx ...

  3. http和ftp下载的区别

    HTTP和FTP是两种网络传输协议的缩写,FTP是File Transportation Protocol(文件传输协议)的缩写,而HTTP则是Hyper Text Transportation Pr ...

  4. 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换

    [源码下载] 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换 作者:webabcd 介绍速战速决 之 PHP ...

  5. .Net 连接FTP下载文件报错:System.InvalidOperationException: The requested FTP command is not supported when using HTTP proxy

    系统环境: Windows + .Net Framework 4.0   问题描述: C#连接FTP下载文件时,在部分电脑上有异常报错,在一部分电脑上是正常的:异常报错的信息:System.Inval ...

  6. Java使用SFTP和FTP两种连接方式实现对服务器的上传下载 【我改】

    []如何区分是需要使用SFTP还是FTP? []我觉得: 1.看是否已知私钥. SFTP 和 FTP 最主要的区别就是 SFTP 有私钥,也就是在创建连接对象时,SFTP 除了用户名和密码外还需要知道 ...

  7. JDBC 连接mysql获取中文时的乱码问题

    前段时间学习JDBC,要连接mysql获取数据.按照老师的样例数据,要存一些名字之类的信息,用的都是英文名,我当时就不太想用英文,就把我室友的名字存了进去,嘿嘿,结果,出问题了. 连接数据库语句: s ...

  8. ftp下载目录下所有文件及文件夹内(递归)

    ftp下载目录下所有文件及文件夹内(递归)   /// <summary> /// ftp文件上传.下载操作类 /// </summary> public class FTPH ...

  9. java ftp下载文件

    1.使用官方正规的jar commons-net-1.4.1.jar jakarta-oro-2.0.8.jar 注意:使用ftp从windows服务器下载文件和从linux服务器下载文件不一样 2. ...

随机推荐

  1. 进程管理之wait和waitpid

    僵尸进程 在介绍wait.waitpid和waitid函数之前,首先要介绍一下僵尸进程,因为,这三个函数的本质任务就是处理僵尸进程的问题. 进程会我们的生命体一样,也有消亡.进程在退出时,内核会清理进 ...

  2. MySQL GROUP BY多个字段分组用法详解

    mysql语句中group by 很容易理解 是分组查询.比如 select sum(score) from user group by name 意思是查询每个人的分数总和但是, select su ...

  3. 基于tgp协议的套接字的 粘包解决

    客户端 import socket import struct import json phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM ...

  4. 一起来学Go --- (go的简介以及环境的安装)

    Go 相信大家,看到这篇文章的时候,已经自己在百度百科了解了go的发展史已经特性,再次我依然....得哔哔叨一会.   ^.^ go语言的特性 go语言作为一门静态类型开发语言,与当前的开发语言想必具 ...

  5. ASP.NET Core开发期间部署到IIS自定义主机域名并附加进程调试

    在.NET Framework环境下,我们经常会这么做 把一个web项目不经过发布直接部署到IIS里去,配置上主机名,修改一下hosts文件,就可以用自定义的域名来访问我们的应用程序,使用附加到进程( ...

  6. 最大流isap模板

    isap+bfs初始化+栈优化,点的编号从0开始: ; ; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow; }ed ...

  7. python在windows和linux环境的进程对比

    1.fork进程:(1)在windows系统中不可以用fork来创建进程,linux可以,但是创建大量进程使用很不方便. 2.Process进程: import multiprocessing as ...

  8. 一步步带你做vue后台管理框架(一)——介绍框架

    系列教程<一步步带你做vue后台管理框架>第一课 github地址:vue-framework-wz 线上体验地址:立即体验 在如今的科技公司中有很多前端的需求都是要写一个类似于后台管理框 ...

  9. Semaphore实现原理分析

    synchronized的语义是互斥锁,就是在同一时刻,只有一个线程能获得执行代码的锁.但是现实生活中,有好多的场景,锁不止一把. 比如说,又到了十一假期,买票是重点,必须圈起来.在购票大厅里,有5个 ...

  10. poj 1742 多重背包

    题意:给出n种面值的硬币, 和这些硬币每一种的数量, 要求求出能组成的钱数(小于等于m) 思路:一开始直接用多重背包套上去超时了,然后就没辙了,然后参考网上的,说只需要判断是否能取到就行了,并不需要记 ...