4

FTP サーバーから XML ファイルをダウンロードして解析するために使用するデータベースにフィードのリストがあります。scrpt は、Windows タスク スケジューラを使用して毎日実行される jar ファイルにまとめられます。場合によっては、特定の xml ファイルを取得する際にリクエストが中断されることがあります。これまでのところ、2 週間で約 3 回発生しており、実際のパターンは確認できません。

めちゃくちゃになったら、実行元のコンピューターに移動します。コマンド ウィンドウが開いているのを確認し、xml が完全にダウンロードされる前に停止します。コマンド ウィンドウを閉じてタスクを手動で実行すると、すべて正常に動作します。

xml ファイルをダウンロードするために使用しているコードは次のとおりです。

private void loadFTPFile(String host, String username, String password, String filename, String localFilename){
        System.out.println(localFilename);
        FTPClient client = new FTPClient();
        FileOutputStream fos = null;

        try {
            client.connect(host);
            client.login(username, password);
            String localFilenameOutput = createFile(assetsPath + localFilename);
            fos = new FileOutputStream(localFilenameOutput);
            client.retrieveFile(filename, fos);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) 
                    fos.close();
                client.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

この関数はループで呼び出され、失敗するとすべてが停止し、スクリプトは次のフィードに進みません。

何が起こっているのかはわかりませんが、接続が失われている可能性がありますが、それが起こっている場合は try/catch がキャッチすると思います。タイムアウトでうまくいくか、スレッドを使用する必要があるかはわかりません(ただし、スレッドを使用したことはありません)

なぜこれが起こっているのか、そして問題を解決するために何ができるのかについて、誰かが私を正しい方向に向けることができますか

4

3 に答える 3

2

UPDATE-データ接続のタイムアウトを設定します

最後のファイルは部分的にしかダウンロードされておらず、ソースが与えられているFTPClient.retrieveFile()ので、サーバー側で問題が発生している可能性があります(ハングするか、死ぬことさえあります-誰が知っていますか)。明らかに、サーバーを修復したり、そこで何が起こっているのかを知ることさえできません。とにかく、タイムアウトを追加して、別の場所にログインし、FTPサーバー管理者に送信する可能性を個別にsetDataTimeout(int)キャッチすることをお勧めしSocketTimeoutExceptionます(時間情報と一緒に)ログをマージして何が問題なのかを確認できるようにします。

古い答え

すべてのファイルに接続してログインしていることに気づかなかったので、以下は制御接続を閉じずに正常にログアウトしないようにするための最適化ですが、問題に対処することはできません。

JVMをデバッグモードで起動し、ハングしたときにデバッガーを接続できます。とにかく、この回答このスレッドによると、ネットワーク機器デバイス(ルーター)のタイムアウトの問題になる可能性があります。FTPClientJavadocから

ファイル転送中、データ接続はビジーですが、制御接続はアイドル状態です。FTPサーバーは、制御接続が使用中であることを認識しているため、アクティビティがないために制御接続を閉じませんが、ネットワークルーターが制御接続とデータ接続が相互に関連付けられていることを認識するのは非常に困難です。一部のルーターは、制御接続をアイドルとして扱い、データ接続を介した転送にルーターの許容アイドル時間よりも長い時間がかかる場合は、制御接続を切断する場合があります。

これに対する1つの解決策は、制御接続を介して安全なコマンド(つまり、NOOP)を送信して、ルーターのアイドルタイマーをリセットすることです。これは次のように有効になります。

ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes
于 2012-08-22T18:57:39.417 に答える
1

いずれかの通話のリターンステータスを確認しますか、それともコードですか?

時々使用しなければならないcompletePendingCommand()の呼び出しがあります。それは調べるべきものかもしれません。

また、IO例外は表示されません。これは、CopyStreamExceptionとして再パッケージ化されると思います。

例外をトラップするため、戻り値をブール値に変更することもできます。少なくとも、呼び出しループは、転送が発生したかどうかを認識します。

private boolean loadFTPFile(String host, String username, String password, String filename, String localFilename){
    System.out.println(localFilename);
    FTPClient client = new FTPClient();
    FileOutputStream fos = null;

    try {
        client.connect(host);

        int reply = client.getReplyCode();

        if (!FTPReply.isPositiveCompletion(reply)){
            client.disconnect();
            System.err.println("FTP server refused connection.");
            return false;
        }


        if (!client.login(username, password)){
            client.logout();
            return false;
        }

        String localFilenameOutput = createFile(assetsPath + localFilename);
        fos = new FileOutputStream(localFilenameOutput);
        boolean result = client.retrieveFile(filename, fos);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        if (result){
            System.out.println("\tFile Transfer Completed Successfully at: " + sdf.format(Calendar.getInstance().getTime()));

            // ftp.completePendingCommand();
        }
        else {
            System.out.println("\tFile Transfer Failed at: " + sdf.format(Calendar.getInstance().getTime()));
        }

    return result;
    }catch (CopyStreamException cse){
        System.err.println("\n\tFile Transfer Failed at: " + sdf.format(Calendar.getInstance().getTime()));
        System.err.println("Error Occurred Retrieving File from Remote System, aborting...\n");
        cse.printStackTrace(System.err);
        System.err.println("\n\nIOException Stack Trace that Caused the Error:\n");
        cse.getIOException().printStackTrace(System.err);
        return false;
    }catch (Exception e){
        System.err.println("\tFile Transfer Failed at: " + sdf.format(Calendar.getInstance().getTime()));
        System.out.println("Error Occurred Retrieving File from Remote System, aborting...");
        e.printStackTrace(System.err);
        return false;
    } finally {
        try {
            if (fos != null) 
                fos.close();
            client.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
于 2012-08-22T18:50:34.787 に答える
0

スレッドの問題ではありません。そのコードは問題なくクリーンアップされるように見えるため、ループ内の何かが原因である可能性があります。とはいえ、テストのために、おそらく追加したいでしょう

catch (Exception e) {
    e.printStackTrace();
}

IOExceptioncatch 句の後。別の例外がスローされている可能性があります。

もう 1 つは、データベースの結果セットから一度に 1 つずつ結果を取得し、FTP 取得を行う場合、問題になる可能性があります。JDBC 呼び出しによってすべての結果が一度に戻されない限り、それもタイムアウトになる可能性があります。すべてのデータベース クエリが実際に結果セット全体を一度にクライアントに返すわけではありません。

于 2012-08-22T18:43:20.407 に答える