当前位置: 首页 > 知识库问答 >
问题:

Apache Commons FTP被动模式,如何设置远程监听端口(数据流)

郏景澄
2023-03-14

我尝试使用apache-commons-net-3.7.2(隐式TLS,使用客户端证书登录/密码进行双因素身份验证)连接FTP服务器。

我可以验证自己,以被动模式进入,但是客户端无法成功连接到服务器以通过数据套接字获取数据。

我可以在同一台计算机上连接自己与WinSCP(相同的设置)。我已激活WinSCP日志以查看协议详细信息,并使用相同的选项调整了源代码。我可以用协议CommandListener验证我的协议是否正常。我知道被动模式是必需的,因为WinSCP发出PASV命令。

我可以看到WinSCP连接到端口62564上的数据套接字(我已将FTP IP地址替换为XXX)

2021-01-06 10:25:35.575 227 Entering Passive Mode (192,168,4,122,244,100).
2021-01-06 10:25:35.575 Server sent passive reply with unroutable address 192.168.4.122, using host address instead.
2021-01-06 10:25:35.575 MLSD
2021-01-06 10:25:35.575 Connexion à 83.XXX.XXX.XXX:62564...
2021-01-06 10:25:35.604 150 Transferring directory

我还可以看到服务器发送的PASV命令的回复不包括要连接的端口。

public class TestApi {
    
    public static void _parseExtendedPassiveModeReply(String reply)
        {
            reply = reply.substring(reply.indexOf('(') + 1,
                    reply.indexOf(')')).trim();
    
            char delim1, delim2, delim3, delim4;
            delim1 = reply.charAt(0);
            delim2 = reply.charAt(1);
            delim3 = reply.charAt(2);
            delim4 = reply.charAt(reply.length()-1);
    
            if (!(delim1 == delim2) || !(delim2 == delim3)
                    || !(delim3 == delim4)) {
                System.out.println("Could not parse extended passive host information.\nServer Reply: " + reply);
            }
    
            int port;
            try
            {
                port = Integer.parseInt(reply.substring(3, reply.length()-1));
            }
            catch (NumberFormatException e)
            {
                System.out.println("Could not parse extended passive host information.\nServer Reply: " + reply);
            }
        }   
    
    public static void main(String[] args) throws SocketException, IOException, GeneralSecurityException {

        String hostname = args[0];
        int port = Integer.parseInt(args[1]);
        String login = args[2];
        String pwd = args[3];

        FTPSClient client = new FTPSClient("TLS",true);
        
        File clientCertStore = new File("myJCEKS keystore");        
        KeyManager keyManager = KeyManagerUtils.createClientKeyManager("JCEKS",clientCertStore,"","myalias","");        
        client.setKeyManager(keyManager);
        
        client.connect(hostname, port);
        int reply = client.getReplyCode();

        if (!FTPReply.isPositiveCompletion(reply)) {
            client.disconnect();
            System.err.println("FTP server refused connection.");
            System.exit(1);
        } else {
            if (client.login(login, pwd)) {
                
                client.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.err), true));
                client.sendCommand("OPTS","UTF8 ON");
                client.sendCommand("PBSZ","0");
                client.sendCommand("PROT","P");
                
                int retour = client.pasv();
                System.out.println(retour);
                _parseExtendedPassiveModeReply(client.getReplyString());                
                
                System.out.println(client.printWorkingDirectory());
                reply = client.getReplyCode();
                System.out.println(reply);
                
                System.out.println(client.listHelp());
                
                //it freezes here, after sending MLDS command 
                //same thing using regular api for listing files (WinSCP use MLSD while regular api uses LIST)      
                client.sendCommand("MLSD");

                //and so on

                System.out.println("LOGOUT");
                client.logout();
            } else {
                System.out.println("echec login");
            }
        }

    }
}

我假设API不知道必须在哪个端口上发送数据请求,并且使用了一个不正常的默认值。我不知道WinSCP是如何成功计算62564端口号的。

OPTS UTF8 ON
200 Command OPTS succeed
PBSZ 0
200 PBSZ=0
PROT P
200 PRIVATE data channel protection level set
PASV
227 Entering Passive Mode (192,168,4,122,245,74).
227
PWD
Could not parse extended passive host information.
Server Reply: 192,168,4,122,245,74
Could not parse extended passive host information.
Server Reply: 192,168,4,122,245,74
257 "/" is current directory
/
257
HELP
214-The following commands are implemented
    ABOR  ACCT  ALLO* APPE  CDUP  CWD   DELE  FEAT+ HELP
    HOST+ LANG+ LIST  MDTM+ MLST+ MKD   MODE  NLST  NOOP
    OPTS+ PASS  PASV  PORT  PWD   QUIT  REIN  REST  RETR
    RMD   RNFR  RNTO  SITE  SIZE  SMNT  STAT  STOR  STOU
    STRU* SYST  TYPE  USER  XCUP  XCRC  XCWD  XMD5  XMKD
    XPWD  XRMD  XSIGN XSHA1 XSHA256 XSHA512 XQUOTA
214 Help complete
214-The following commands are implemented
    ABOR  ACCT  ALLO* APPE  CDUP  CWD   DELE  FEAT+ HELP
    HOST+ LANG+ LIST  MDTM+ MLST+ MKD   MODE  NLST  NOOP
    OPTS+ PASS  PASV  PORT  PWD   QUIT  REIN  REST  RETR
    RMD   RNFR  RNTO  SITE  SIZE  SMNT  STAT  STOR  STOU
    STRU* SYST  TYPE  USER  XCUP  XCRC  XCWD  XMD5  XMKD
    XPWD  XRMD  XSIGN XSHA1 XSHA256 XSHA512 XQUOTA
214 Help complete

MLSD

经过几个小时的搜索在API留档,源代码,FTP RFC,我不知道如何做到这一点。

共有1个答案

司徒焕
2023-03-14

你的假设是错误的。你没有设置端口。服务器告诉你要连接到哪个端口。

对于WinSCP:

2021-01-06 10:25:35.575 227进入被动模式(192168,4122244100)
<2021-01-06 10:25:35.575连接。XXX。XXX。XXX:62564。。。

其中62564=(244

请参见RFC 959,第4.1.2节。传输参数命令,第28页。

由于使用了错误的代码,PASV响应的解析失败。\u parseExtendedPassiveModeReply用于EPSV。对于PASV,请使用\u parsepassiveemodereply。在这里,您还将看到上述公式的实现:

int oct1 = Integer.parseInt(m.group(2));
int oct2 = Integer.parseInt(m.group(3));
__passivePort = (oct1 << 8) | oct2;
 类似资料:
  • 本文向大家介绍如何用Node监听80端口?相关面试题,主要包含被问及如何用Node监听80端口?时的应答技巧和注意事项,需要的朋友参考一下 这题有陷阱!在类Unix系统中你不应该去监听80端口,因为这需要超级用户权限。因此不推荐让你的应用直接监听这个端口。 目前,如果你一定要让你的应用80端口的话,你可以有通过在Node应用的前方再添加一层反向代理(例如nginx)来实现,如下图。否则,建议你直接

  • Server可以监听多个端口,每个端口都可以设置不同的协议处理方式,例如80端口处理http协议,9507端口处理TCP协议。SSL/TLS传输加密也可以只对特定的端口启用。 !> 例如主服务器是WebSocket或Http协议,新监听的TCP端口(listen的返回值,即Swoole\Server\Port,以下简称port)默认会继承主Server的协议设置。必须单独调用port对象的set方

  • 问题内容: 我刚刚在Windows上安装了node.js。我有一个不运行的简单代码: 我得到:错误:听EADDRINUSE 是否有一个 配置文件 告诉node.js在特定端口上侦听? 问题是我已经让Apache监听了端口80。 编辑: 问题答案: 没有配置文件,除非您自己创建一个。但是,端口是函数的参数。例如,侦听端口8124: 如果查找打开的端口时遇到问题,可以转到命令行并输入: 查看每个适配器

  • 我有一个基本回收适配器,如下所示: : 基本视图保持架为: 假设ViewHolder有两个视图,一个TextView和一个ImageView。如何对ViewHolder的itemview中的所有项目实现ClickListener

  • 我正在寻找任何类型的端口监听器,可以查看UDP连接。原因是我试图编写一个程序,查看人们在游戏中聊天的内容,并做出相应的回应。[并希望创建一个服务器自动化来举办锦标赛] 我尝试了一个VB.NET解决方案,但是尽管花了几个小时试图让它并排连接,但它还是会关闭连接。 代码不完整,但这是我需要的自动取款机。

  • 我有一个Tomcat 9.0.60服务器,运行在Linux上的OpenJDK 1.8.0上,其中netstat-ltpn | grep java显示它侦听的端口不止配置的端口: (我从该列表中删除了所有配置的端口。) 因此,我认为有几个应用程序也打开了“他们自己的”套接字,他们听。我想找出每个端口的哪个Java线程正在侦听,这样我就可以进一步找出应用程序,也许它仍然是必需的,或者只是开发人员忘记的