Setting connect timeout for FtpClient
Asked Answered
R

4

9

When using ftpClient.connect with an existing host who has no ftp service active, timeout occurs only after 5 minutes, which is much too long.

I tried setting diverse timeouts (setDefaultTimeout, setDataTimeout) which did not change anything.

FtpClient inherits from SocketClient which has a setConnectTimeout method, but when I use this I get a java.lang.NoSuchMethodError: org/apache/commons/net/ftp/FTPClient.setConnectTimeout when running it. This seems to be because of some J2SW 1.2 compatibility, as described in Commons-net FAQ:

Q: How can I set a connection timeout? http://wiki.apache.org/commons/Net/FrequentlyAskedQuestions

They suggest to implement an own SocketFactory creating objects from an extended Socket class using a specific timeout. However, when trying to use ftpClient.setSocketFactory I also get a java.lang.NoSuchMethodError.

Any help how I can reduce the connect timeout?

Ragsdale answered 11/6, 2012 at 12:14 Comment(4)
Mentioned FAQ question & answer says that: Since Commons Net 1.2.x has a J2SE 1.2 compatibility requirement, the ability to specify a connect timeout is not included. meaning that Commons Net 1.2.x libraries doesn't have desired functionality. Do you need specifically that old version of library? Otherwise, try newer or newest version of it e.g. Commons Net 3.1 - there FTPClient class has setConnectTimeout method doing exactly what you need as mentioned in the answer(s) below.Ravenna
I use FTPClient 3.1, my Eclipse shows no errors, but after deploying on the application server, it gives the mentioned errors. Mavne build pom.xml has the identical dependency version, and the ear file includes the correct jar.Ragsdale
This is really strange since this should work... Did you tried connecting from simple public static void main(String[] args) method from under Eclipse? Maybe the problem is in application server: it may provide older version of Commons Net library and your deployed application may use FTPClient from there ...Ravenna
Yes this works. This is running within weblogic 10.3.5. Maybe there is an older commons-net in the classpath somehow included by weblogic itself having precedence?Ragsdale
R
3

Though there is possible solution for that older version of Commons Net library, I suggest to figure out why wrong version of Commons Net is used. To do this you may include following code to the place where FTPClient is used in your webapp:

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
}

In case if FTPClient is loaded not by java.net.URLClassLoader then it may get more complicated to check the classpath, though it should not be a problem.

Hope this helps...

Ravenna answered 13/6, 2012 at 12:50 Comment(3)
The array consists of 14 entries: 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, ... not including the commons-net library I have bundled in my ear-deployment.Ragsdale
Hmm, that's strange. Never worked with weblogic, but it looks like following question/answer is close to what you need: #3376546Ravenna
Indeed, some specific work is due to set the precedence of conflicting classes for classloader so the ones bundled are loaded first.Apiece
C
11
    FTPClient ftp = new FTPClient();

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

From Apache docs:

   /**
     * 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)
Cauthen answered 10/2, 2017 at 16:47 Comment(0)
L
4

It must be in the way your calling the setConnectTimeout, because it does exist. setConnectTimeout is not a static call, you must call it after you allocate the FTPClient object and do the set prior to the connect.

FTPClient ftp = new FTPClient();
ftp.setConnectTimeout(5000); // 5000 Milliseconds (5 Seconds)
... 
ftp.connect(server, port); 
Licence answered 11/6, 2012 at 13:45 Comment(1)
Has to be your setup then. I'm using the commons-net-3.0.1.jar. I tried it in eclipse just to make sure. You may want to check and make sure you don't have an older jar file being loaded first.Licence
R
3

Though there is possible solution for that older version of Commons Net library, I suggest to figure out why wrong version of Commons Net is used. To do this you may include following code to the place where FTPClient is used in your webapp:

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
}

In case if FTPClient is loaded not by java.net.URLClassLoader then it may get more complicated to check the classpath, though it should not be a problem.

Hope this helps...

Ravenna answered 13/6, 2012 at 12:50 Comment(3)
The array consists of 14 entries: 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, ... not including the commons-net library I have bundled in my ear-deployment.Ragsdale
Hmm, that's strange. Never worked with weblogic, but it looks like following question/answer is close to what you need: #3376546Ravenna
Indeed, some specific work is due to set the precedence of conflicting classes for classloader so the ones bundled are loaded first.Apiece
R
2

Just to add some clarification for these values (after manually testing a lot of combinations, and just to mention that this is related to spring DefaultFtpSessionFactory using underneath apache FTPClient - so applies in the end to that one):

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());
Retroaction answered 6/5, 2021 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.