FTPClient 超时处理

apache 开源库:commons-net 超时处理。

Socket有2个阻塞

第1个阻塞:TCP的三次握手 connectTimeout

TCP通过三次握手,建立连接,这个过程,类似我们在信号不好的时候打电话的过程:
客户端:喂,能听到我说话吗
服务端:我能听到,你能听到我吗
客户端:能听到

        Socket socket = new Socket();
        socket.connect(new InetSocketAddress("localhost", 8080));

当 socket 客户端执行 socket.connect() 方法时,客户端请求和服务端建立tcp连接时,会一直阻塞直到连接建立成功,或抛异常。当设置了connectTimeout, 客户端请求和服务端建立连接时,阻塞时间超过connectTimeout时,就会抛出异常java.net.ConnectException: Connection timed out: connect。

第2个阻塞:读取输入流 soTimeout

        Socket socket = new Socket();
        socket.connect(new InetSocketAddress("localhost", 8080));
        socket.getInputStream().read();

当调用socket.getInputStream().read()方法时,由于这个read()方法是阻塞的,read()方法会一直处于阻塞状态等待接受数据,直到服务端往输出流中响应数据 而导致不能往下执行代码;而setSoTimeout()方法就是设置阻塞的超时时间.当设置了超时时间后,如果read()方法读不到数据,处于等待读取数据的状态时,就会开始计算超时时间;当到达超时时间还没有新的数据可以读取的时候,read()方法就会抛出io异常,结束read()方法的阻塞状态;如果到达超时时间前,从缓冲区读取到了数据,那么就重新计算超时时间.当不设置这个参数时,默认值为无穷大,即InputStream的read方法会一直阻塞下去,除非连接断开。

FTPClient 一共有 6 个设置超时的接口,而不管是文件上传或下载,这过程,FTP 都会创建两个 Socket,一个用于传输控制命令,一个用于传输文件数据,超时接口和这两个 Socket 之间的关系如下:

setConnectTimeout() 用于设置终端 Socket 与 FTP 服务器建立连接这个过程的超时时间。

setDefaultTimeout() 用于设置终端的传输控制命令的 Socket 的 SoTimeout,即针对传输控制命令的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。

setSoTimeout() 作用跟上个方法一样,区别仅在于该方法设置的超时会覆盖掉上个方法设置的值。

setDataTimeout() 用于设置终端的传输数据的 Socket 的 Sotimeout,即针对传输文件数据的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。

setControlKeepAliveTimeout() 用于设置当处于传输数据过程中,按指定的时间阈值定期让传输控制命令的 Socket 发送一个无操作命令 NOOP 给服务器,让它 keep alive。

setControlKeepAliveReplyTimeout():只有调用上个方法后,该方法才能生效,用于设置在传输数据这个过程中,暂时替换掉传输控制命令的 Socket 的 SoTimeout,传输过程结束恢复这个 Socket 原本的 SoTimeout。

超时接口大概的用途明确了,那么再稍微来讲讲该怎么用:

针对使用 FTPClient 下载 FTP 文件,一般只需使用三个超时接口,

setDefaultTimeout(毫秒)用于设置传输控制命令的 Socket 的 SoTimeout 的超时处理,

一个是 setConnectTimeout(毫秒),用于设置建立连接过程中的超时处理,

而另一个则是 setDataTimeout(毫秒),用于设置传输数据的 Socket 的 SoTimeout 的超时处理,

    public boolean login(String ip, int port, String username, String password) {
        ftpClient = new FTPClient();
        try {
            logger.info("connecting...ftp服务器:" + ip + ":" + port);
            ftpClient.setControlEncoding("UTF-8");// 编码设置必须放在connect前不然不起作用
            ftpClient.setConnectTimeout(5000);//tcp握手连接超时,单位毫秒
            // SoTimeout读超时,服务端flush到输出流的间隔时间,也就是服务端多久时间内必须flush(或者close)一次到输出流。
            // 传输数据不会发送一个数据包,SoTimeout不是指整个传输时间,而是指两个数据包之间的间隔时间。
            ftpClient.setDefaultTimeout(10000);//传输控制命令的SoTimeout,一个命令等待响应结果的超时时间,单位毫秒
            ftpClient.setDataTimeout(10000);//传输数据的SoTimeout,单位毫秒
            //下面2个一般成对出现
            ftpClient.setControlKeepAliveTimeout(60);//传输数据这个过程中,传输控制命令的心跳(保活)时间,单位秒,tcp网络编程中一般设置心跳为300秒
            ftpClient.setControlKeepAliveReplyTimeout(10000);//传输数据这个过程中,暂时替换掉传输控制命令的SoTimeout,单位毫秒
            ftpClient.connect(ip, port); // 连接ftp服务器
            ftpClient.login(username, password); // 登录ftp服务器
            ftpClient.setRemoteVerificationEnabled(false);//取消服务器获取自身Ip地址和提交的host进行匹配,否则当不一致时报出以上异常。
            ftpClient.enterLocalPassiveMode();//被动模式,PASV模式。通知服务器打开一个数据端口,客户端将连接到这个端口进行数据传输。
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.setBufferSize(1024);
            int replyCode = ftpClient.getReplyCode(); // 是否成功登录服务器
            if (FTPReply.isPositiveCompletion(replyCode)) {
                logger.info("连接成功...ftp服务器:" + ip + ":" + port);
                return true;
            }
            ftpClient.setSoTimeout(10000);//同setDefaultTimeout,会覆盖setDefaultTimeout,单位毫秒,这个参数要连接成功以后设置,否则报错空指针异常
            logger.info("连接失败...ftp服务器:" + ip + ":" + port);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
        }
        return false;
    }

梳理之后,FTPClient 一共有 6 个设置超时的接口,而不管是文件上传或下载,这过程,FTP 都会创建两个 Socket,一个用于传输控制命令,一个用于传输文件数据,超时接口和这两个 Socket 之间的关系如下:

setConnectTimeout() 用于设置终端 Socket 与 FTP 服务器建立连接这个过程的超时时间。
setDefaultTimeout() 用于设置终端的传输控制命令的 Socket 的 SoTimeout,即针对传输控制命令的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。
setSoTimeout() 作用跟上个方法一样,区别仅在于该方法设置的超时会覆盖掉上个方法设置的值。
setDataTimeout() 用于设置终端的传输数据的 Socket 的 Sotimeout,即针对传输文件数据的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。
setControlKeepAliveTimeout() 用于设置当处于传输数据过程中,按指定的时间阈值定期让传输控制命令的 Socket 发送一个无操作命令 NOOP 给服务器,让它 keep alive。
setControlKeepAliveReplyTimeout():只有调用上个方法后,该方法才能生效,用于设置在传输数据这个过程中,暂时替换掉传输控制命令的 Socket 的 SoTimeout,传输过程结束恢复这个 Socket 原本的 SoTimeout。


 

参考:

查看ftp是否存在阻塞_记录 FTPClient 超时处理的相关问题_weixin_39906130的博客-CSDN博客

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值