赞
踩
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博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。