How to increase ftp download speed for multiple files [Java]

I implemented Java code to upload files to a server from org.apache.commons.net.ftp.FTPClient For several files, ftp download speed is very slow. How can I improve the speed.

-Change the library? What is a powerful FTP client class library for uploading multiple files?

- Use multiple threads? How can I implement ftp download function with multiple threads? Can someone show me an example? I am new to multithreaded programming.


After I read the whole answer, I will try to change my code and test it.

The following is an example FTPClient code:

// create instance of FTPClient FTPClient ftp = new FTPClient(); ftp.setControlEncoding("UTF-8"); ftp.setDefaultTimeout(30000); // connect to server try { ftp.connect("10.1.1.1", 990); } catch(Exception e) { System.out.println("Cannot connect to server"); return; } // login to server if (!ftp.login("username", "password")) { ftp.logout(); System.out.println("Cannot login to server"); return; } try { ftp.setFileTransferMode(FTP.BINARY_FILE_TYPE); ftp.enterLocalPassiveMode(); // ftp.setBufferSize(0); <-- someone suggest me to set buffer size to 0, but it throw error sometime. } catch(Exception e) { } // create directory on server // dirs is list of required directories on server for (String dir : dirs) { try { ftp.makeDirectory(dir); } catch(IOException e) { } } // files is a map of local file and string of remote file // such as // file on client is "C://test/a.txt" // location on server is "/test/a.txt" for (Map.Entry<File, String> entry : files.entrySet()) { File localFile = entry.getKey(); String remoteFile = entry.getValue(); FileInputStream input = null; try { input= new FileInputStream(localFile); ftp.storeFile(remoteFile, input); } catch (Exception e) { try { ftp.deleteFile(remoteFile); } catch (IOException e1) { } } finally { if (input != null) { try { input.close(); } catch (IOException e) { } } } } // disconnect if (ftp != null && ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException f) { // do nothing } } 

When I downloaded 1050 files (each file is about 1-20 KB), it took about 49406 - 51000 milliseconds (this is just the download time). I would like to improve speed.

Some people suggest I use ftp4j, but when I test a library with 1050 files, ftp4j download speed is slower than FTPClient, about 10,000 milliseconds. it took about 60,000 milliseconds.

The following is an example ftp4j code:

 // create instance of FTPClient FTPClient ftp = new FTPClient(); ftp.setCharset("UTF-8"); // connect to server try { ftp.connect("10.1.1.1", 990); } catch(Exception e) { System.out.println("Cannot connect to server") return; } // login to server try { ftp.login("username", "password"); } catch (Exception e) { try { ftp.logout(); } catch (Exception e1) { } System.out.println("Cannot login to server") return; } try { ftp.setType(FTPClient.TYPE_BINARY); ftp.setPassive(true); } catch(Exception e) { } // create directory on server // dirs is list of required directories on server for (String dir : dirs) { try { ftp.createDirectory(dir); } catch (Exception e) { } } // files is a map of local file and string of remote file // such as // file on client is "C://test/a.txt" // location on server is "/test/a.txt" for (Map.Entry<File, String> entry : files.entrySet()) { final File localFile = entry.getKey(); final String remoteFile = entry.getValue(); BufferedInputStream input = null; boolean success = false; try { input = new BufferedInputStream(new FileInputStream(localFile)); // ftp.upload(localFile); <-- if I use ftp.upload(File), it will took more time. ftp.upload(remoteFile, input, 0, 2048, new MyTransferListener()); success = true; } catch (Exception e) { } finally { if (input != null) { try { input.close(); } catch (IOException e) { } } if (!success) { try { ftp.deleteFile(remoteFile); } catch (Exception e) { } } } } // disconnect if (ftp != null && ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException f) { // do nothing } } 

I am trying to use multiple threads.

The following is a multiple code:

 final CountDownLatch latch = new CountDownLatch(files.size()); ExecutorService pool = Executors.newFixedThreadPool(10); for (Map.Entry<File, String> entry : files.entrySet()) { final File localFile = entry.getKey(); final String remoteFile = entry.getValue(); pool.execute(new Runnable() { public void run() { FileInputStream input = null; try { input= new FileInputStream(localFile); ftp.storeFile(remoteFile, input); } catch (Exception e) { try { ftp.deleteFile(remoteFile); } catch (IOException e1) { } } finally { if (input != null) { try { input.close(); } catch (IOException e) { } } latch.countDown(); } } }); } try { // waiting for all threads finish // see: http://stackoverflow.com/questions/1250643/how-to-wait-for-all-threads-to-finish-using-executorservice latch.await(); } catch(Exception e) { } 

Is it correct? It works correctly, but it cannot improve speed. it took about 49000 - 51000 milliseconds, the same as the code without the stream.

I am testing speed using an intranet. The Internet will take more time.

How can I do to increase download speed?

+4
source share
2 answers

I don’t know why, but Apache Commons FTP downloads rather slowly, I had the same problem and could not solve it.

Now I use FTP4j , it is very similar to apache commons ftp, but the download is very fast.

This is an example:

 FTPClient client = new FTPClient(); client.connect("www.yoursite.com"); client.login("login", "password"); client.setPassive(true); client.setType(FTPClient.TYPE_BINARY); client.changeDirectory("a"); File f = new File("path/to/your/file"); client.upload(f); client.disconnect(true); 

In this library, I deleted a 340KB file in less than one second, and with Apache Commons FTP it took about 1 minute.

If you want to transfer different files using streams, try putting each client.upload(f) in a different stream, but I'm not sure if it will increase the transfer.


Quote @fge previous answer:

In principle, most likely you cannot.

Do not forget that FTP has two types of channels: command channel and data channels. One download is initiated by sending instructions on the command channel to open the data channel for the actual download.

Now:

  • most FTP servers are configured so that one command channel can only open one data channel at any time;
  • bandwidth limits exist: your upstream bandwidth and server bandwidth down.

Is it possible to upload multiple files at the same time, i.e. open more than one data channel, you would have a problem with the fact that the overhead of TCP itself actually slowed down the boot process as a whole.

Basically: keep one data channel open at all times. Trying and discovering more than one is simply not worth it. It can work in ~ 1% of cases in general. It's just not worth the hassle.

+1
source

This is Q & Some possible explanations of what happens: why ftp is loading slowly in java 7

In addition, it offers several workarounds:

  • Update to snapshot 3.3, which you can (currently) find here

  • Call FTPClient.setBufferSize(0) .

Apparently, there is also a regression in Java 7 for Windows, where the firewall application filter for the FTP client blocks the client from using the PASV FTP protocol. It is not clear which is the best solution for this, but you can try the following:

  • Modify the Windows firewall to disable the firewall application filter (as described on the Microsoft KB page.

  • Change the FTP application to "active" mode ... although this requires that the FTP server can initiate connections to the machine your clients are running on.

Note. There seems to be more than one explanation for the problem ... or maybe several possible problems.

0
source

Source: https://habr.com/ru/post/1490118/


All Articles