• org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication


    Ftp问题

    最近遇到了ftp读取中文乱码的问题,代码中使用的是FtpClient。google一下找到了解决方案。

    FTP协议里面,规定文件名编码为iso-8859-1,FTP类中默认的编码也是这个。

    public FTP() {
        this.setDefaultPort(21);
        this._replyLines = new ArrayList();
        this._newReplyString = false;
        this._replyString = null;
        this._controlEncoding = "ISO-8859-1";
        this._commandSupport_ = new ProtocolCommandSupport(this);
    }
    

    参考文章 https://www.cnblogs.com/chenfei0801/p/3427310.html 设置了编码格式

    private FTPClient getClient(ConnectReq connectReq) {
        String host = StringUtils.substringBefore(connectReq.getConnectUrl(), ":");
        int port = Integer.parseInt(StringUtils.substringAfter(connectReq.getConnectUrl(), ":"));
    
        log.info("Connect to Ftp [{}:{}] with user [{}] and passwd [{}].",
                host, port, ftpReq.getUserName(), ftpReq.decodePassword());
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient.connect(host, port);
            log.info("Connected.");
            ftpClient.login(ftpReq.getUserName(), ftpReq.decodePassword());
            // Use passive mode to pass firewalls.
            if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(
                    "OPTS UTF8", "ON"))) {
                LOCAL_CHARSET = UTF8_CHARSET;
            }
            ftpClient.setControlEncoding(LOCAL_CHARSET);
            ftpClient.enterLocalPassiveMode();
            log.info("Logged.");
            return ftpClient;
        } catch (IOException e) {
            log.error("连接ftp服务-{} 出错,原因:{}", ftpReq.getHost(), e);
            throw new InnerException(ErrorCode.DSOURCE_ERROR, e);
        }
    }
    

    发现程序能够连接成功,但是在调用client.logout方法时出现了错误。

    org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication.
    	at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:313)
    	at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:290)
    	at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:479)
    	at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:552)
    	at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:601)
    	at org.apache.commons.net.ftp.FTP.quit(FTP.java:809)
    	at org.apache.commons.net.ftp.FTPClient.logout(FTPClient.java:979)
    	...
    
    java.lang.RuntimeException: org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication.
    ...
    Caused by: org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication.
    	at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:313)
    	at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:290)
    	at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:479)
    	at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:552)
    	at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:601)
    	at org.apache.commons.net.ftp.FTP.quit(FTP.java:809)
    	at org.apache.commons.net.ftp.FTPClient.logout(FTPClient.java:979)
    	... 28 more
    

    根据FTPClient官方文档的解释

        /***
         * Logout of the FTP server by sending the QUIT command.
         * <p>
         * @return True if successfully completed, false if not.
         * @exception FTPConnectionClosedException
         *      If the FTP server prematurely closes the connection as a result
         *      of the client being idle or some other reason causing the server
         *      to send FTP reply code 421.  This exception may be caught either
         *      as an IOException or independently as itself.
         * @exception IOException  If an I/O error occurs while either sending a
         *      command to the server or receiving a reply from the server.
         ***/
        public boolean logout() throws IOException
        {
            return FTPReply.isPositiveCompletion(quit());
        }
    

    这个错误的出现的可能原因是ftp服务器过早关闭或者其他原因导致服务端返回了421

    继续追踪到后面的异常栈

    Connection closed without indication.

    这个问题可能是因为FTP服务器服务有故障,或是是网络问题。于是我立马用命令行尝试连接到Ftp上,果然是可以连的,证明ftp服务没问题。那么就是网络问题了。

    检查了代码,在代码中使用的是被动模式。FTP服务器一般使用20和21两个端口与客户端进行通信,21端口用来传输FTP的控制命令,20端口用于传输文件数据。

    如果是主动模式的话,FTP客户端向服务器的FTP控制端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路;当需要传送数据时,客户端在命令链路上用PORT的命令告诉服务器我开放了某端口,你过来连接我。于是服务器从20端口向客户端的该端口发送连接请求,建立一条数据链路来传送数据。在数据链路建立过程中是服务器主动请求,所以称为主动模式。

    graph LR subgraph 客户端 client[客户端] clientPort[打开端口] client--2.打开-->clientPort end subgraph 服务端 server[服务端] server-->port21 server-->port20 port21(21端口) port20(20端口) client--1.连接请求-->port21 client--3.PORT通知-->server port20--4.建立连接-->clientPort end

    如果是被动模式的话,FTP客户端向服务器的FTP控制端口(默认21)发送连接请求,服务器接受连接,建立一条命令链路;当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端,我打开了某端口,你过来连我。于是客户端向服务器的该端口发送连接请求,建立一条数据链路来传送数据。在数据链路建立的过程中是服务器被动等待客户机的请求,所以称被动模式。

    graph LR subgraph 客户端 client[客户端] clientConnect[建立数据链路] client-->clientConnect end subgraph 服务端 server[服务端] server-->port21 server--2.打开-->serverPort port21(21端口) serverPort(打开端口) client--1.连接请求-->port21 server--3.PASV通知-->client clientConnect--4.建立连接-->serverPort end

    上文说到代码中用的是被动模式,也就意味着服务端需要打开21端口和另一个端口供客户端连接。我使用的ftp是用docker装的,只透出了21端口,所以使用被动模式连接会出错。于是把这里改成主动模式,连接成功。

  • 相关阅读:
    Odd sum CodeForces
    Chips CodeForces
    Secrets CodeForces
    Voting CodeForces
    Jury Meeting CodeForces
    Planning CodeForces
    Maxim Buys an Apartment CodeForces
    Chemistry in Berland CodeForces
    Monitor CodeForces
    Four Segments CodeForces
  • 原文地址:https://www.cnblogs.com/CodingJacob/p/12067811.html
Copyright © 2020-2023  润新知