今天项目中要下载快钱的对账单,快钱对账单文件的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. JAVA在win10上的安装环境配置

    [TOC] 第一步: 打开右击电脑选择属性 第二步: 选择高级系统设置 第三部: 选择环境变量 第四部: 选择在系统变量中新建:JAVA_HOME 属性值为你的java的jdk的位置比如我的:E:\J ...

  2. 【Zookeeper】角色、顺序号、读写机制

    角色 leader 负责进行投票的发起和决议,更新系统状态 learner 包括follower和observer follower用于接受客户端请求并向客户端返回结果,在选举过程中参与投票 obse ...

  3. Mybatis映射原理,动态SQL,log4j

    1.理清mybatis中的#和$之间的区别? #{ }:表示一个预处理参数,参数类型不定,是根据传入的参数类型来设定的. 类似于JDBC中的? 特例使用,模糊查询:(针对oracle): and us ...

  4. 聊聊GIS中那些坐标系

    从第一次上地图学的课开始,对GIS最基本的地图坐标系统就很迷.也难怪,我那时候并不是GIS专业的学生,仅仅是一门开卷考试的专业选修课,就没怎么在意. 等我真正接触到了各种空间数据产品,我才知道万里长征 ...

  5. Jmeter之解决烦人的中文乱码问题

    Jmeter是一款国外开源工具,所以就跟LR一样,对中文的支持不是很好,经常会有同学录制脚本后回放或者是发送HTTP请求,看到响应报文里面有乱码! 那如何才能解决这个问题呢?我们分2个情况来分析: 一 ...

  6. zoj3785 What day is that day?

    It's Saturday today, what day is it after 11 + 22 + 33 + ... + NN days? Input There are multiple tes ...

  7. Servlet知识点

    如果请求采用Get方式,则重写doGet()方法,如果请求采用Post方式,则重写doPost()方法. 下面是重写doGet()方法的servlet例子. servlet继承如下类: 整体结构: 在 ...

  8. JavaScript入门(四)

    一.数组 1.数组的基本概念 数组是在内存空间中连续存储的一组有序数据的集合.元素在数组中的顺序,称为下标.可以使用下标访问数组的每个元素. 2.如何声明一个数组 ①使用字面量声明:var arr = ...

  9. 【找不到与请求 URI匹配的 HTTP 资源】(转)

    在.net下,创建一个HTTP服务,有很多方案,比较老ashx,一般处理程序(HttpHandler), Web Service SOAP协议的,数据格式是XML,HTTP协议         WCF ...

  10. C# 导出数据到Excel模板中(转)

    今天做报表的时候遇到了多表头的问题,而且相应的报表的格式都一样.所以就采用了报表模板的方式来进行. 第一步:在开发的当前项目中引入:Microsoft.Office.Interop.Excel:Sys ...