問題解決:ftp併發讀取文件內容時,會出現ftp連接數過多,進而導致讀取文件出現問題

場景

ftp併發讀取文件內容時,過了一段時候,連接數過多,進而導致讀取文件出現問題,被ftp服務器給限制了。截圖如下:
在這裏插入圖片描述

環境

軟件 版本
centos 7
jdk 8

問題原因

原來的操作代碼如下:

InputStream in = null;
ByteArrayOutputStream output = null;
try {
    in = ftpClient.retrieveFileStream(ftpFilePath);
    output = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024 * 4];
    int len = 0;
    while ((len = in.read(buffer)) != -1) {
        output.write(buffer, 0, len);
    }
} catch (Exception e) {
    throw e;
} finally {
    if (in != null) {
        in.close();
    }
    if (output != null) {
        output.close();
    }
}

這個是讀取文件內容到程序的變量裏面去,而不落地到本地文件,減少本地IO交互。程序執行完畢之後,就會關閉對應的流。但是就是這裏出現了問題,沒有等待ftp服務器返回響應,就直接關閉了流。官方解釋,有幾種FTPClient方法是沒辦法完成整個FTP命令序列,進而完成事務的。所以這些命令要求我們在收到肯定的中間命令後採取一些措施來保證整個事務的完成。而我們的代碼完成其操作後,必須調用completePendingCommand來接收來自服務器的完成答覆並驗證整個事務是否成功。
在這裏插入圖片描述
所以,問題出現的原因是沒有調用completePendingCommand來完成整個事務,導致ftp連接頻繁掛掉,然後不斷重新啓動新的ftp連接,導致連接數過多,被ftp服務器給限制了。

解決方案

1. 官方方案

下面是官方提供的解決方法:

InputStream input;
OutputStream output;
input  = new FileInputStream("foobaz.txt");
output = ftp.storeFileStream("foobar.txt")
if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
    input.close();
    output.close();
    ftp.logout();
    ftp.disconnect();
    System.err.println("File transfer failed.");
    System.exit(1);
}
Util.copyStream(input, output);
input.close();
output.close();
// Must call completePendingCommand() to finish command.
if(!ftp.completePendingCommand()) {
    ftp.logout();
    ftp.disconnect();
    System.err.println("File transfer failed.");
    System.exit(1);
}

2. 本文的解決方法

在關閉流的時候,判斷是否完成,以下爲解決方法代碼:

InputStream in = null;
ByteArrayOutputStream output = null;
try {
    in = ftpClient.retrieveFileStream(ftpFilePath);
    output = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024 * 4];
    int len = 0;
    while ((len = in.read(buffer)) != -1) {
        output.write(buffer, 0, len);
    }
} catch (Exception e) {
    throw e;
} finally {
    if (in != null) {
        in.close();
    }
    if (output != null) {
        output.close();
    }
    if (ftp != null) {
        // completePendingCommand 不能執行兩次
        if (!ftp.getClient().completePendingCommand()) {
            log.warn("ftp 關閉連接,對應的ITEM信息如下:{}",itemInfo);
        }
    }
}

結果

使用命令netstat -an|grep :21來檢測ftp連接數,結果如下:
在這裏插入圖片描述
觀察程序運行結果,過了一個小時,未發現異常。問題得到解決。
在這裏插入圖片描述

總結

使用FTPClient的相關方法的時候,記得查看相關的文檔,裏面已經有比較完善的解決措施。

隨緣求贊

如果我的文章對大家產生了幫忙,可以在文章底部點個贊或者收藏;
如果有好的討論,可以留言;
如果想繼續查看我以後的文章,可以左上角點擊關注
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章