FtpClient一定要setSotimeOut、setDataTimeout

本文详细解释了`SocketOptions#SO_TIMEOUT`选项的作用,它用于设置Socket在读取数据时的超时时间,防止因网络波动导致的无限期阻塞。在FTP连接中,通常需要设置默认连接超时、数据传输超时和SO_TIMEOUT以确保程序在长时间无响应时能够正常退出。示例代码展示了如何在FTPClient中设置这些超时值,确保FTP连接的稳定性和可靠性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SotimeOut,简单说就是读取数据时阻塞链路的超时时间。

/**
  *  Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
  *  with the specified timeout, in milliseconds. With this option set
  *  to a non-zero timeout, a read() call on the InputStream associated with
  *  this Socket will block for only this amount of time.  If the timeout
  *  expires, a <B>java.net.SocketTimeoutException</B> is raised, though the
  *  Socket is still valid. The option <B>must</B> be enabled
  *  prior to entering the blocking operation to have effect. The
  *  timeout must be {@code > 0}.
  *  A timeout of zero is interpreted as an infinite timeout.
  *  (设置一个超时时间,用来当这个 Socket 调用了 read() 从 InputStream 输入流中
  *    读取数据的过程中,如果线程进入了阻塞状态,那么这次阻塞的过程耗费的时间如果
  *    超过了设置的超时时间,就会抛出一个 SocketTimeoutException 异常,但只是将
  *    线程从读数据这个过程中断掉,并不影响 Socket 的后续使用。
  *    如果超时时间为0,表示无限长。)
  *  (注意,并不是读取输入流的整个过程的超时时间,而仅仅是每一次进入阻塞等待输入流中
  *    有数据可读的超时时间)
  * @param timeout the specified timeout, in milliseconds.
  * @exception SocketException if there is an error
  * in the underlying protocol, such as a TCP error.
  * @since   JDK 1.1
  * @see #getSoTimeout()
  */
 public synchronized void setSoTimeout(int timeout) throws SocketException {
    //.....
 }

/**
  *  Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
  *  with the specified timeout, in milliseconds. With this option set
  *  to a non-zero timeout, a read() call on the InputStream associated with
  *  this Socket will block for only this amount of time.  If the timeout
  *  expires, a <B>java.net.SocketTimeoutException</B> is raised, though the
  *  Socket is still valid. The option <B>must</B> be enabled
  *  prior to entering the blocking operation to have effect. The
  *  timeout must be {@code > 0}.
  *  A timeout of zero is interpreted as an infinite timeout.
  *  (设置一个超时时间,用来当这个 Socket 调用了 read() 从 InputStream 输入流中
  *    读取数据的过程中,如果线程进入了阻塞状态,那么这次阻塞的过程耗费的时间如果
  *    超过了设置的超时时间,就会抛出一个 SocketTimeoutException 异常,但只是将
  *    线程从读数据这个过程中断掉,并不影响 Socket 的后续使用。
  *    如果超时时间为0,表示无限长。)
  *  (注意,并不是读取输入流的整个过程的超时时间,而仅仅是每一次进入阻塞等待输入流中
  *    有数据可读的超时时间)
  * @param timeout the specified timeout, in milliseconds.
  * @exception SocketException if there is an error
  * in the underlying protocol, such as a TCP error.
  * @since   JDK 1.1
  * @see #getSoTimeout()
  */
 public synchronized void setSoTimeout(int timeout) throws SocketException {
    //.....
 }

/**
  * Sets the timeout in milliseconds to use when reading from the
  * data connection.  This timeout will be set immediately after
  * opening the data connection, provided that the value is &ge; 0.
  * <p>
  * <b>Note:</b> the timeout will also be applied when calling accept()
  * whilst establishing an active local data connection.
  * @param  timeout The default timeout in milliseconds that is used when
  *        opening a data connection socket. The value 0 means an infinite timeout.
  */
 public void setDataTimeout(int timeout)
 {
     __dataTimeout = timeout;
 } 

/**
  * Sets the timeout in milliseconds to use when reading from the
  * data connection.  This timeout will be set immediately after
  * opening the data connection, provided that the value is &ge; 0.
  * <p>
  * <b>Note:</b> the timeout will also be applied when calling accept()
  * whilst establishing an active local data connection.
  * @param  timeout The default timeout in milliseconds that is used when
  *        opening a data connection socket. The value 0 means an infinite timeout.
  */
 public void setDataTimeout(int timeout)
 {
     __dataTimeout = timeout;
 }

如果不设置,可能会在网络波动时阻塞,至此无限时阻塞在此!!!

所以使用ftp时,一般需要设置timeout来保证程序正常运行(不卡死)。

FTPClient ftpClient = null;
try {
    ftpClient = new FTPClient();
    ftpClient.setDefaultTimeout(10000);
    ftpClient.setConnectTimeout(10000);
    ftpClient.setDataTimeout(10000);

    // 连接FTP服务器
    ftpClient.connect(host, port);
    // 登陆FTP服务器
    ftpClient.login(userName, password);
    // 中文支持
    ftpClient.setControlEncoding("UTF-8");
    // 设置文件类型为二进制(如果从FTP下载或上传的文件是压缩文件的时候,不进行该设置可能会导致获取的压缩文件解压失败)
    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
    // 主动模式
    //ftpClient.enterLocalActiveMode();
    // 被动模式 每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据 防止假卡死
    ftpClient.enterLocalPassiveMode();

    if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
        logger.error("连接FTP失败");
        ftpClient.disconnect();
    } else {
        ftpClient.setSoTimeout(10000);
        logger.info("FTP连接成功!");
    }
} catch (Exception e) {
    e.printStackTrace();
    logger.error("登陆FTP失败,请检查FTP相关配置信息是否正确!", e);
}
return ftpClient;

FTPClient ftpClient = null;
try {
    ftpClient = new FTPClient();
    ftpClient.setDefaultTimeout(10000);
    ftpClient.setConnectTimeout(10000);
    ftpClient.setDataTimeout(10000);

    // 连接FTP服务器
    ftpClient.connect(host, port);
    // 登陆FTP服务器
    ftpClient.login(userName, password);
    // 中文支持
    ftpClient.setControlEncoding("UTF-8");
    // 设置文件类型为二进制(如果从FTP下载或上传的文件是压缩文件的时候,不进行该设置可能会导致获取的压缩文件解压失败)
    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
    // 主动模式
    //ftpClient.enterLocalActiveMode();
    // 被动模式 每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据 防止假卡死
    ftpClient.enterLocalPassiveMode();

    if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
        logger.error("连接FTP失败");
        ftpClient.disconnect();
    } else {
        ftpClient.setSoTimeout(10000);
        logger.info("FTP连接成功!");
    }
} catch (Exception e) {
    e.printStackTrace();
    logger.error("登陆FTP失败,请检查FTP相关配置信息是否正确!", e);
}
return ftpClient;

### 安卓 FTP 监听断开连接的解决方案 在 Android 平台上实现 FTP 服务时,可能会遇到监听断开连接的问题。这通常与网络环境变化、超时设置不当或客户端行为有关。以下是一些可能的原因分析及对应的解决方法。 #### 原因一:网络不稳定或中断 如果设备在网络切换(例如从 Wi-Fi 到移动数据)或其他情况下失去连接,则可能导致 FTP 会话终止。可以通过增加重新连接机制来缓解这一问题。 ```java public void reconnectIfDisconnected() { try { if (!ftpClient.isConnected()) { // 检查当前是否已断开连接 ftpClient.connect(serverAddress, port); // 尝试重新建立连接 ftpClient.login(username, password); } } catch (IOException e) { Log.e("FTP", "Reconnection failed: ", e); } } ``` 上述代码片段展示了如何检测并尝试恢复断开的 FTP 连接[^1]。 --- #### 原因二:超时时间过短 某些场景下,默认的读取或写入超时时间不足以完成复杂的文件传输任务。可以调整 `setSoTimeout` 和其他相关参数以延长等待时间。 ```java ftpClient.setConnectTimeout(30000); // 设置连接超时时间为30秒 ftpClient.setDataTimeout(60000); // 设置数据传输超时时间为60秒 ``` 通过适当扩展这些超时值,能够减少由于短暂延迟引发的意外断连情况。 --- #### 原因三:未正确处理异常退出 当用户手动停止 FTP 服务或者程序崩溃时,如果没有妥善释放资源,下次启动可能出现兼容性错误甚至完全无法访问。因此建议始终遵循良好的实践原则——无论成功与否都要关闭所有打开的对象实例。 ```java finally { if (ftpClient != null && ftpClient.isConnected()) { try { ftpClient.logout(); ftpClient.disconnect(); } catch (Exception ex) {} } } ``` 以上部分强调了清理工作的必要性,从而避免残留状态影响后续操作。 --- #### 使用异步 I/O 提升稳定性 对于长时间运行的任务来说,同步阻塞模型容易受到外部因素干扰而失败;相比之下,基于回调的通知型架构更加灵活可靠。具体而言就是利用 Java NIO 或者第三方框架支持下的非阻塞方式管理输入/输出流。 > **注意**: 虽然这种方法理论上能带来更好的用户体验,但在实际开发过程中需权衡复杂度增益之间的关系[^3]。 --- 最后提醒一点关于依赖项冲突方面的小贴士:如果你发现项目编译期间存在莫名其妙的错误消息提示找不到类定义之类的状况,请记得核查 build.gradle 文件里是否有重复引入相同功能却版本号不同的库文件现象发生。按照之前提到过的做法把它们统一放到名为libs子目录下面去应该就可以解决问题啦[^2]! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天代码码天天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值