简体   繁体   English

在 Android 模拟器中从本地 FTP 服务器下载时出现错误“227 进入被动模式”/“连接被拒绝”

[英]Error "227 Entering Passive Mode"/"Connection refused" when downloading from local FTP server in Android emulator

I am trying to download a file from my local FileZilla Server with Java FTPSClient running in Android emulator.我正在尝试使用在 Android 模拟器中运行的 Java FTPSClient从本地 FileZilla 服务器下载文件。

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;
}

I call this function like this:我这样称呼这个函数:

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());
    }...

But I keep getting this error:但我不断收到此错误:

I/System.out: 220-FileZilla Server version 0.9.41 beta
I/System.out: 220-written by Tim Kosse (Tim.Kosse@gmx.de)
              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)

I already tried to use enterLocalActivemode() instead of enterLocalPassivmode() but it didn't help.我已经尝试使用enterLocalActivemode()而不是enterLocalPassivmode()但它没有帮助。 The FTP server is TLS enforcing and running on my local machine. FTP 服务器在我的本地机器上执行和运行 TLS。 I am connecting to it through 10.0.2.2 (Android loopback).我通过 10.0.2.2(Android 环回)连接到它。 How can I fix this?我怎样才能解决这个问题?

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.虽然我不熟悉 Android Emulator,但我假设您需要连接到 10.0.2.2 才能连接到模拟器主机。

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).在 FTP 被动模式下,服务器发回一个 IP 地址,FTP 客户端需要连接到该地址来传输文件(或目录列表)。 As your FTP server listens on 127.0.0.1, it sends back that IP address.当您的 FTP 服务器侦听 127.0.0.1 时,它会发回该 IP 地址。 But 127.0.0.1 refers to the (emulated) Android host, in the context of your Android code.但是 127.0.0.1 指的是(模拟的)Android 主机,在您的 Android 代码上下文中。 Hence the "connection refused".因此,“连接被拒绝”。

This is pretty much similar to a common problem with connecting to an FTP server behind a NAT.这与连接到 NAT 后面的 FTP 服务器的常见问题非常相似。 See FTP server running on Port 2000 over NAT not working on Passive Mode请参阅通过 NAT 在端口 2000 上运行的 FTP 服务器无法在被动模式下工作

And the solution is hence the same:因此解决方案是相同的:

  • In FileZilla Server Interface, go to Edit > Settings > Passive mode settings > IPv4 specific > External Server IP Address for passive mode transfers .在 FileZilla 服务器界面中,转到编辑 > 设置 > 被动模式设置 > IPv4 特定 > 被动模式传输的外部服务器 IP 地址 And enter 10.0.2.2.并输入 10.0.2.2。
  • Maybe you will also need to uncheck "Don't use external IP for local connections" .也许您还需要取消选中“不要将外部 IP 用于本地连接”

Obviously this in turn makes the FTP server unusable for normal clients.显然,这反过来又使普通客户端无法使用 FTP 服务器。

And you have correctly commented, this problem only arise when connecting from Android emulator to an FTP server running on emulator host.并且您已正确评论,此问题仅在从 Android 模拟器连接到在模拟器主机上运行的 FTP 服务器时出现。


Another solution is using FTPClient.setPassiveNatWorkaroundStrategy .另一种解决方案是使用FTPClient.setPassiveNatWorkaroundStrategy It accepts an implementation of HostnameResolver interface.它接受HostnameResolver接口的实现。 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.如果您以将 127.0.0.1 转换为 10.0.2.2 的方式实现,即使服务器上没有任何更改,它也将允许您的 Java 代码连接。

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();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM