问题描述
我正在尝试使用运行在Android模拟器中的Java FTPSClient
从本地FileZilla服务器下载文件.
I am trying to download a file from my local FileZilla Server with Java FTPSClient
running in Android emulator.
我已经编写了此帮助程序代码来下载一个文件:
I've written this helpercode to download one File:
public boolean downloadSingleFile(FTPSClient ftpClient,
String remoteFilePath, File downloadFile) {
OutputStream outputStream;
Log.i("t1", remoteFilePath + " - " + downloadFile.getAbsolutePath());
try {
outputStream = new BufferedOutputStream(new FileOutputStream(
downloadFile));
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
boolean retval = ftpClient.retrieveFile(remoteFilePath, outputStream);
outputStream.flush();
return retval;
} catch (Exception e) {
Log.e("dwFile", e.toString());
Log.e("dwFile", ftpClient.getReplyString());
} return false;
}
我这样称呼这个函数:
FTPSClient dwClient = new FTPSClient();
dwClient.addProtocolCommandListener(
new PrintCommandListener(
new PrintWriter(new OutputStreamWriter(System.out, "UTF-8")), true));
dwClient.setConnectTimeout(30 * 1000);
dwClient.connect(OmsSettingsFunctions.getFTPServer());
Log.i("dwDB", dwClient.getReplyString());
if (dwClient.login(FPTuser, FTPpass)) {
Log.i("dwDB", dwClient.getReplyString());
dwClient.enterLocalPassiveMode();
File dwFile = new File(externalPath + "/Android/data/com.myapp/files/Documents/db.temp");
if(!downloadSingleFile(dwClient, "/DBs/db.txt", dwFile)) {
Log.e("dwDB", "Download could not finish (DB)");
Log.e("dwDB", dwClient.getReplyString());
}...
但我一直收到此错误:
I/System.out: 220-FileZilla Server version 0.9.41 beta
I/System.out: 220-written by Tim Kosse ([email protected])
220 Please visit http://sourceforge.net/projects/filezilla/
I/System.out: AUTH TLS
D/EGL_emulation: eglMakeCurrent: 0xa209dd60: ver 3 0 (tinfo 0x9f652ff0)
D/EGL_emulation: eglMakeCurrent: 0xa209dd60: ver 3 0 (tinfo 0x9f652ff0)
I/System.out: 234 Using authentication type TLS
I/dwDB: 234 Using authentication type TLS
I/Permission: Readingpermission is granted
I/Permission: Writingpermission is granted
I/System.out: USER *******
I/System.out: 331 Password required for omstest
I/System.out: PASS *******
I/System.out: 230 Logged on
I/dwDB: 230 Logged on
I/t1: /DBs/db.txt - /storage/0FF0-280B/Android/data/com.myapp/files/Documents/db.temp
I/System.out: TYPE I
I/System.out: 200 Type set to I
I/System.out: PASV
I/System.out: 227 Entering Passive Mode (127,0,0,1,199,113)
E/dwFile: java.net.ConnectException: Connection refused
227 Entering Passive Mode (127,0,0,1,199,113)
E/dwDB: Download could not finish (DB)
227 Entering Passive Mode (127,0,0,1,199,113)
我已经尝试使用enterLocalActivemode()
而不是enterLocalPassivmode()
,但是它没有帮助. FTP服务器是TLS强制实施并在我的本地计算机上运行.我正在通过10.0.2.2(Android回送)连接到它.我该如何解决?
I already tried to use enterLocalActivemode()
instead of enterLocalPassivmode()
but it didn't help. The FTP server is TLS enforcing and running on my local machine. I am connecting to it through 10.0.2.2 (Android loopback). How can I fix this?
推荐答案
虽然我对Android Emulator不熟悉,但我认为您需要连接到10.0.2.2才能连接到模拟器主机.
While I'm not familiar with Android Emulator, I assume that you need to connect to 10.0.2.2 to connect to the emulator host machine.
在FTP被动模式下,服务器发回FTP客户端需要连接到的IP地址以传输文件(或目录列表).当您的FTP服务器侦听127.0.0.1时,它会发回该IP地址.但是,在您的Android代码的上下文中,127.0.0.1指的是(模拟的)Android主机.因此,连接被拒绝".
In an FTP passive mode, the server sends back an IP address to which the FTP client needs to connect to transfer a file (or a directory listing). As your FTP server listens on 127.0.0.1, it sends back that IP address. But 127.0.0.1 refers to the (emulated) Android host, in the context of your Android code. Hence the "connection refused".
这与连接到NAT后面的FTP服务器的常见问题非常相似.请参见通过NAT在Port 2000上运行的FTP服务器无法在被动模式下运行
This is pretty much similar to a common problem with connecting to an FTP server behind a NAT. See FTP server running on Port 2000 over NAT not working on Passive Mode
因此解决方案是相同的:
And the solution is hence the same:
- 在FileZilla服务器界面中,转到编辑">设置">被动模式设置">特定于IPv4">用于被动模式传输的外部服务器IP地址" .然后输入10.0.2.2.
- 也许您还需要取消选中不要将外部IP用于本地连接" .
- In FileZilla Server Interface, go to Edit > Settings > Passive mode settings > IPv4 specific > External Server IP Address for passive mode transfers. And enter 10.0.2.2.
- Maybe you will also need to uncheck "Don't use external IP for local connections".
显然,这又使FTP服务器无法用于普通客户端.
Obviously this in turn makes the FTP server unusable for normal clients.
您已正确评论,仅当从Android模拟器连接到在模拟器主机上运行的FTP服务器时,才会出现此问题.
And you have correctly commented, this problem only arise when connecting from Android emulator to an FTP server running on emulator host.
另一个解决方案是使用FTPClient.setPassiveNatWorkaroundStrategy
.它接受HostnameResolver
接口的实现.如果您以将127.0.0.1转换为10.0.2.2的方式实现,则即使服务器上没有任何更改,它也将允许Java代码进行连接.
Another solution is using FTPClient.setPassiveNatWorkaroundStrategy
. It accepts an implementation of HostnameResolver
interface. If you implement in a way that it translates 127.0.0.1 to 10.0.2.2, it will allow your Java code to connect even with out any change on the server.
public static class ServerResolverImpl implements HostnameResolver {
private FTPClient client;
public ServerResolverImpl(FTPClient client) {
this.client = client;
}
@Override
public String resolve(String hostname) throws UnknownHostException {
return this.client.getRemoteAddress().getHostAddress();
}
}
这篇关于错误"227进入被动模式"/“连接被拒绝".在Android模拟器中从本地FTP服务器下载时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!