【问题标题】:Setting connect timeout for FtpClient为 FtpClient 设置连接超时
【发布时间】:2012-06-14 08:19:14
【问题描述】:

ftpClient.connect 与没有激活 ftp 服务的现有主机一起使用时,超时仅在 5 分钟后发生,这太长了。

我尝试设置不同的超时(setDefaultTimeout、setDataTimeout),但这并没有改变任何东西。

FtpClient 继承自 SocketClient,它有一个 setConnectTimeout 方法,但是当我使用它时,我在运行它时得到一个 java.lang.NoSuchMethodError: org/apache/commons/net/ftp/FTPClient.setConnectTimeout。这似乎是因为某些 J2SW 1.2 兼容性,如 Commons-net FAQ 中所述:

问:如何设置连接超时? http://wiki.apache.org/commons/Net/FrequentlyAskedQuestions

他们建议实现自己的SocketFactory,使用特定的超时从扩展的 Socket 类创建对象。但是,当尝试使用 ftpClient.setSocketFactory 时,我也会得到一个 java.lang.NoSuchMethodError

有什么帮助我可以减少连接超时吗?

【问题讨论】:

  • 提到的常见问题解答问题和答案说:Since Commons Net 1.2.x has a J2SE 1.2 compatibility requirement, the ability to specify a connect timeout is not included. 表示 Commons Net 1.2.x 库没有所需的功能。您是否特别需要旧版本的库?否则,请尝试更新或最新版本,例如Commons Net 3.1 - FTPClient 类有 setConnectTimeout 方法完全符合您在下面的答案中提到的需要。
  • 我使用 FTPClient 3.1,我的 Eclipse 没有显示错误,但是在应用服务器上部署后,它给出了上述错误。 Mavne build pom.xml 依赖版本一致,ear 文件包含正确的jar。
  • 这真的很奇怪,因为这应该可以工作...您是否尝试过在 Eclipse 下通过简单的public static void main(String[] args) 方法进行连接?也许问题出在应用程序服务器上:它可能提供旧版本的 Commons Net 库,您部署的应用程序可能会从那里使用 FTPClient ...
  • 是的,这行得通。这是在 weblogic 10.3.5 中运行的。也许在类路径中有一个较旧的公共网络以某种方式被 weblogic 本身包含在优先级?

标签: java ftp-client apache-commons-net


【解决方案1】:
    FTPClient ftp = new FTPClient();

    ftp.setDefaultTimeout();
    ftp.setDataTimeout();
    ftp.setConnectTimeout();
    ftp.setSoTimeout();
    ftp.setControlKeepAliveTimeout();
    ftp.setControlKeepAliveReplyTimeout();

来自 Apache 文档:

   /**
     * Set the default timeout in milliseconds to use when opening a socket.
     * This value is only used previous to a call to
     * {@link #connect connect()}
     * and should not be confused with {@link #setSoTimeout setSoTimeout()}
     * which operates on an the currently opened socket.  _timeout_ contains
     * the new timeout value.
     * <p>
     * @param timeout  The timeout in milliseconds to use for the socket
     *                 connection.
     */
    void setDefaultTimeout(int 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.
     */
    void setDataTimeout(int timeout)
    /**
     * Sets the connection timeout in milliseconds, which will be passed to the {@link java.net.Socket} object's
     * connect() method.
     * @param connectTimeout The connection timeout to use (in ms)
     * @since 2.0
     */
    void setConnectTimeout(int connectTimeout);
    /**
     * Set the timeout in milliseconds of a currently open connection.
     * Only call this method after a connection has been opened
     * by {@link #connect connect()}.
     * <p>
     * To set the initial timeout, use {@link #setDefaultTimeout(int)} instead.
     *
     * @param timeout  The timeout in milliseconds to use for the currently
     *                 open socket connection.
     * @exception SocketException If the operation fails.
     * @throws NullPointerException if the socket is not currently open
     */
    void setSoTimeout(int timeout) throws SocketException;
    /**
     * Set the time to wait between sending control connection keepalive messages
     * when processing file upload or download.
     *
     * @param controlIdle the wait (in secs) between keepalive messages. Zero (or less) disables.
     * @since 3.0
     * @see #setControlKeepAliveReplyTimeout(int)
     */
    void setControlKeepAliveTimeout(long controlIdle);

    /**
     * Set how long to wait for control keep-alive message replies.
     *
     * @param timeout number of milliseconds to wait (defaults to 1000)
     * @since 3.0
     * @see #setControlKeepAliveTimeout(long)
     */
    void setControlKeepAliveReplyTimeout(int timeout)

【讨论】:

    【解决方案2】:

    它一定是你调用 setConnectTimeout 的方式,因为它确实存在。 setConnectTimeout 不是静态调用,您必须在分配 FTPClient 对象后调用它,并在连接之前进行设置。

    FTPClient ftp = new FTPClient();
    ftp.setConnectTimeout(5000); // 5000 Milliseconds (5 Seconds)
    ... 
    ftp.connect(server, port); 
    

    【讨论】:

    • 那么必须是您的设置。我正在使用 commons-net-3.0.1.jar。我在eclipse中试过只是为了确定。您可能需要检查并确保您没有先加载较旧的 jar 文件。
    【解决方案3】:

    虽然对于旧版本的 Commons Net 库有可能的解决方案,但我建议弄清楚为什么使用了错误版本的 Commons Net。为此,您可以在您的 web 应用程序中使用 FTPClient 的位置添加以下代码:

    FTPClient ftpClient = ...;
    if(ftpClient.getClass().getClassLoader() instanceof java.net.URLClassLoader) {
        URL[] urls = ((java.net.URLClassLoader) ftpClient.getClass().getClassLoader()).getURLs();
        // log these urls somewhere and check - these are urls from where your FTPClient may be loaded from
    }
    

    如果FTPClient 不是由java.net.URLClassLoader 加载的,那么检查类路径可能会变得更加复杂,但这应该不是问题。

    希望这会有所帮助...

    【讨论】:

    • 该数组由14个条目组成:weblogic/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar、weblogic/jrmc-4.0.1-1.6.0/lib/tools.jar、weblogic/utils /config/10.3/config-launch.jar, weblogic/wlserver_10.3/server/lib/weblogic_sp.jar, weblogic/wlserver_10.3/server/lib/weblogic.jar, ...不包括我的commons-net库已捆绑在我的耳朵部署中。
    • 嗯,这很奇怪。从未使用过 weblogic,但看起来以下问题/答案与您需要的很接近:stackoverflow.com/questions/3376046/…
    • 确实,一些具体的工作是由于为类加载器设置冲突类的优先级,因此首先加载捆绑的类。
    【解决方案4】:

    只是为这些值添加一些说明(在手动测试了很多组合之后,只是提到这与使用下面的 apache FTPClient 的 spring DefaultFtpSessionFactory 有关 - 所以最后适用于那个):

    import org.springframework.integration.ftp.session.DefaultFtpSessionFactory;
    
    DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
    
    /**
     * Controls 2 values:
     * 1. protected abstract void connect(SocketAddress address, int timeout) throws IOException;
     * --> controls timeout when opening socket connection. this one is by default 0 in java-code,
     * but since OS is controlling this it has some default value - for me in win.
     * it was ~20 seconds. If set to lower value it will be respected. If set >20 in my case,
     * it always treats it as if 20 was set
     * 2. _socket_.setSoTimeout(connectTimeout);
     * --> controls timeout after socket is open (so if FTP server is not responding after
     * socket is successfully connected). Default is unlimited so good to set to some sane value
     * otherwise if no response from FTP Server, connection will hang. Overwrites setDefaultTimeout
     * if already set - but only for this connection time (not after FTP server responds first time
     * with some data).
     */
    factory.setConnectTimeout((int) Duration.ofMinutes(1).toMillis());
    
    /**
     * Controls timeout after socket is open (so if FTP server is not responding after socket is
     * successfully connected).(IF NOT ALREADY SET IN setConnectTimeout),
     * but also controls timeout when reading data from socket after the connection has been made.
     * So if FTP client sends "LIST /" command, and there is no answer from FTP server, without
     * setting this it will hang (since default is 0). Set to some sane value
     * (since server can actually be busy with creating listing of folders for longer time etc.).
     */
    factory.setDefaultTimeout((int) Duration.ofMinutes(1).toMillis());
    
    /**
     * Controls how long to wait if there is a socket inactivity during FILE-related operations.
     * E.g. if we start to download some file from FTP server, this timeout is respected.
     * This is by default set to 0 (that is infinite wait). If set to 10 seconds, and there is at
     * least some activity in communication (eg. every 9 seconds something is received) then there
     * will be no timeout. Only if there is some delay/inactivity for longer than 10 seconds then
     * there will be socketRead0 timeout exception. Should be set, since this is not affected by
     * setConnectTimeout or setDefaultTimeout.
     */
    factory.setDataTimeout((int) Duration.ofMinutes(1).toMillis());
    

    【讨论】:

      猜你喜欢
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 2017-09-18
      • 2012-05-01
      • 1970-01-01
      • 2014-07-28
      • 2014-11-18
      相关资源
      最近更新 更多