Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
apache commons FTPSClient.listFiles()触发java.net.ConnectException:连接被拒绝:连接_Java_Ftps_Apache Commons Net - Fatal编程技术网

apache commons FTPSClient.listFiles()触发java.net.ConnectException:连接被拒绝:连接

apache commons FTPSClient.listFiles()触发java.net.ConnectException:连接被拒绝:连接,java,ftps,apache-commons-net,Java,Ftps,Apache Commons Net,我用Java编写了一个程序,连接到FTPS服务器,在某个父目录中循环查找名称与给定regexp匹配的文件,然后将这些文件检索到本地计算机。我正在使用ApacheCommonsNet3.6和Java8。下面是我如何连接并访问需要迭代的文件夹列表。fileType是字符串输入参数,可以为null。fileNameRegExp也是一个字符串输入参数,其中包含的regexp将仅过滤具有正确命名的文件: String server = "<here I type the dot-separ

我用Java编写了一个程序,连接到FTPS服务器,在某个父目录中循环查找名称与给定regexp匹配的文件,然后将这些文件检索到本地计算机。我正在使用ApacheCommonsNet3.6和Java8。下面是我如何连接并访问需要迭代的文件夹列表。fileType是字符串输入参数,可以为null。fileNameRegExp也是一个字符串输入参数,其中包含的regexp将仅过滤具有正确命名的文件:

String server = "<here I type the dot-separated IP address for the FTPS server>";
int port = <port number>;
String user = "username";
String pass = "********";

String folder = "C:\\Target\\InputFiles\\";

String protocol = "TLS";
int timeoutInMillis = 30000;
FTPSClient sftpClient = new FTPSClient(protocol, true);
int reply ;

try {
    sftpClient.setDataTimeout(timeoutInMillis);
    sftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));

    FTPClientConfig clientConfig = new FTPClientConfig(FTPClientConfig.SYST_NT);

    sftpClient.configure(clientConfig);
    sftpClient.connect(server, port);
    sftpClient.setKeepAlive(Boolean.TRUE);
    sftpClient.login(user, pass);
    reply = sftpClient.getReplyCode();
    System.out.println("INFO: ftp login status = <"+reply+">.");

    sftpClient.enterLocalPassiveMode();
    sftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    sftpClient.execPBSZ(0);
    sftpClient.execPROT("P");

    sftpClient.changeWorkingDirectory("/main_folder");
    reply = sftpClient.getReplyCode();

    System.out.println("INFO: ftp CWD command on /main_folder status = <"+reply+">.");

    List<String> ftpDirectories = new ArrayList<>();

    if( fileType!= null && !fileType.isEmpty() ) {
        ftpDirectories.add("/main_folder/"+fileType);
    } else {
        FTPFile[] ftpDirList = sftpClient.listDirectories();
        for( FTPFile dir : ftpDirList)
            ftpDirectories.add("/main_folder/"+dir.getName());
    }

    for( String workDirectory : ftpDirectories) {
        sftpClient.changeWorkingDirectory(workDirectory);

        FTPFile[] ftpFiles = Arrays.stream(sftpClient.listFiles())
                                   .filter(file -> file.getName().matches(fileNameRegExp))
                                   .toArray(FTPFile[]::new);

        for (FTPFile ftpFile : ftpFiles) {

            (...here's the file transfer logic for each FTPFile found...)

        }

    }

}catch(Exception ex){
    
}
到目前为止还不错。文件被读取并通过套接字复制到本地文件夹。现在,当代码找到另一个文件时,我遇到了麻烦。调用sftpClient.listFiles()返回空。如果出于调试目的,我尝试检查返回的数组是否为空,并尝试第二次调用sftpClient.listFiles(),则会得到一个异常:java.net.ConnectException:Connection拒绝:connect

有趣的是,就在这之前,我调用了sftpClient.isConnected()和sftpClient.isAvailable(),两者都返回true

在这一点上,我所关心的是创建代码列表并传输第二个文件,所以我更改代码以在流到达第二个文件的子文件夹时转移流。在新的流程中,我注销、断开连接,再次执行所有FTPSClient设置,因为断开连接会重置对象中的一些内容,重新连接、再次登录和预启动。它读取并传输文件。当然,这是个骗局。我知道它在哪里失败,设置了一个带断开和重新连接的绕道,所以这不是解决方案。在这里,我完全处于黑暗之中,没有想法。我运行了我知道的检查,以确保套接字仍然可用并工作,并且程序仍然连接到远程服务器,但仍然失败。连接/套接字似乎有问题,但除非有一个测试我可以运行,这样我就知道它过时了,否则我永远不知道什么时候需要断开/重新连接程序才能继续

正如最后一句话,我必须检查FTPS服务器的唯一方法是通过FileZilla连接,使用完全相同的用户名、密码、服务器ip和端口,这样可以很好地工作。它列出了/main_文件夹中的目录,我可以查看和重命名树中的所有文件,并可以来回传输文件。我无法使用控制台连接到它,也无法通过cmd或bash调用sftp

我欢迎您提出任何关于如何解决此问题或获得更多关于此bug的见解

提前谢谢你,并致以亲切的问候

更新

我想感谢@AllinProgram的建议,但不幸的是结果是一样的。这是我的超控:

@Override
protected void _prepareDataSocket_(final Socket socket) throws IOException {
    if(socket instanceof SSLSocket) {
        // Control socket is SSL
        final SSLSession session = ((SSLSocket) _socket_).getSession();
        final SSLSessionContext context = session.getSessionContext();
        //context.setSessionCacheSize(0);
        try {
            final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
            sessionHostPortCache.setAccessible(true);
            final Object cache = sessionHostPortCache.get(context);
            final Method method = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
            method.setAccessible(true);
            String key = String.format("%s:%s", socket.getInetAddress().getHostName(),    String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
            method.invoke(cache, key, session);
                   key = String.format("%s:%s", socket.getInetAddress().getHostAddress(), String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
            method.invoke(cache, key, session);
        }
        catch(NoSuchFieldException e) {
            // Not running in expected JRE
            System.out.println("No field sessionHostPortCache in SSLSessionContext. Exception: " + e);
        }
        catch(Exception e) {
            // Not running in expected JRE
            System.out.println(e.getMessage());
        }
    }
}
在我的主方法类中,我调用
System.setProperty(“jdk.tls.useExtendedMasterSecret”,“false”)

不过,在进一步调试之后,我注意到了一件事。listFiles()实际上会触发LIST命令的新数据连接(调用父类中的
受保护套接字\u openDataConnection(String命令,String arg)
,这会触发对FTP类中的
public int pasv()
的调用)。当目录中没有匹配的文件时,代码会发出CWD、PASV和列表。当有文件匹配时,它是CWD、PASV、LIST、PASV、RETR。然后,对于下面的目录,当listFiles()被触发时,PASV命令返回一个250回复。此时发出的最后一个命令是CWD,也有250个回复。发出FTP命令所调用的方法如下:

public int sendCommand(String command, String args) throws IOException {
        if (this._controlOutput_ == null) {
            throw new IOException("Connection is not open");
        } else {
            String message = this.__buildMessage(command, args);
            this.__send(message);
            this.fireCommandSent(command, message);
            this.__getReply();
            return this._replyCode;
        }
    }
PASV应该返回227,但这个电话给我250。它几乎就像在运行一样,但是回复代码卡在了CWD回复代码中,该代码为250。这会导致openDataConnection为套接字返回一个
null
,并且
私有FTPListParseEngine initiateListParsing(FTPFileEntryParser解析器,字符串路径名)
返回一个FTPListParseEngine对象,该对象不读取当前工作目录中的文件服务器列表。这就是listFiles()返回空FTPFile数组的原因

我尝试重写sendCommand以获得一个带有227的PASV(在上一个PASV之后发出一个新的PASV),但是当代码尝试连接到套接字时,我得到了java.net.ConnectException:连接被拒绝,几乎就像服务器没有侦听该端口一样,但是是服务器返回了数据套接字的套接字详细信息,对吗?我的意思是,这是PASV的结果:服务器告诉客户端去哪里检索数据。为什么它会拒绝连接


我希望这对某些人来说是有意义的,因为一个250帕斯卡的车没有意义。我在这里迷路了o/

试试这个。覆盖_prepareDataSocket u()。谢谢你,@AllinProgram,但它不起作用。我已经用这个信息和其他附加信息更新了帖子
@Override
protected void _prepareDataSocket_(final Socket socket) throws IOException {
    if(socket instanceof SSLSocket) {
        // Control socket is SSL
        final SSLSession session = ((SSLSocket) _socket_).getSession();
        final SSLSessionContext context = session.getSessionContext();
        //context.setSessionCacheSize(0);
        try {
            final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
            sessionHostPortCache.setAccessible(true);
            final Object cache = sessionHostPortCache.get(context);
            final Method method = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
            method.setAccessible(true);
            String key = String.format("%s:%s", socket.getInetAddress().getHostName(),    String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
            method.invoke(cache, key, session);
                   key = String.format("%s:%s", socket.getInetAddress().getHostAddress(), String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
            method.invoke(cache, key, session);
        }
        catch(NoSuchFieldException e) {
            // Not running in expected JRE
            System.out.println("No field sessionHostPortCache in SSLSessionContext. Exception: " + e);
        }
        catch(Exception e) {
            // Not running in expected JRE
            System.out.println(e.getMessage());
        }
    }
}
public int sendCommand(String command, String args) throws IOException {
        if (this._controlOutput_ == null) {
            throw new IOException("Connection is not open");
        } else {
            String message = this.__buildMessage(command, args);
            this.__send(message);
            this.fireCommandSent(command, message);
            this.__getReply();
            return this._replyCode;
        }
    }