2016-08-31 7 views
0

EmbarcaderoのC++ 10 Seattleで書かれたVCLアプリケーションがあります。メインスレッドは、転送中に接続が失われた場合、Getメソッドが無期限にハングするため、TIdFTP機能を実行するスレッドを生成します。このアイデアは、接続が掛かっているかどうかを検出し、スレッドを孤立させ、「再試行」を開始することです。私の問題は、私は、仕事関数を実装し....スレッド内のTIdFTPが起動しない作業方法

class FTPThread : public TThread 
{ 
protected: 
    void __fastcall Execute(); 
    void __fastcall UpdateUI(); 
public: 
    __fastcall FTPThread(bool CreateSuspended); 
    String FTPhostname; 
    String FTPusername; 
    String FTPpassword; 
    String remoteDir; 
    String localDir; 
    String localTempDir; 
    String fileName; 
    TIdFTP *FTPClnt; 
    void __fastcall FTPClntWorkBegin(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCountMax); 
    void __fastcall FTPClntWorkEnd(TObject *ASender, TWorkMode AWorkMode); 
    void __fastcall FTPClntWork(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCount); 
    void __fastcall FTPClntAfterGet(TObject *ASender, TStream *AStream); 

}; 

を次の私は、スレッドのHファイル内のオブジェクトを宣言しただけでなく、火災すべき方法(WorkBegin、WorkEnd、仕事、など)が好きですGETは、転送を開始し、完了すると、このようなスレッドのCPPファイルで.....これらのメソッドの

void __fastcall FTPThread::UpdateUI() 
{ 
    if (FrmFTP) { 
     //FrmFTP->FTPProg->Max = fileSizeBytes; 
     FrmFTP->FTPProg->Position = ftpProgress; 
     FrmFTP->BringToFront(); 
     Application->ProcessMessages(); 
    } 
} 

void __fastcall FTPThread::FTPClntWorkBegin(TObject *ASender, 
    TWorkMode AWorkMode, __int64 AWorkCountMax) { 
    ftpProgress = 0; 
    if (FrmFTP) { 
     FrmFTP->FTPProg->Max = fileSizeBytes; 
    } 
    Synchronize(&UpdateUI); 
} 
// --------------------------------------------------------------------------- 

void __fastcall FTPThread::FTPClntWorkEnd(TObject *ASender, 
    TWorkMode AWorkMode) 

{ 
    if (FrmFTP) { 
     ftpProgress = FrmFTP->FTPProg->Max; 
    } 
    Synchronize(&UpdateUI); 
} 
// --------------------------------------------------------------------------- 

void __fastcall FTPThread::FTPClntWork(TObject *ASender, TWorkMode AWorkMode, 
    __int64 AWorkCount) 

{ 
    ftpProgress = AWorkCount; 
    Synchronize(&UpdateUI); 
} 
// --------------------------------------------------------------------------- 

void __fastcall FTPThread::FTPClntAfterGet(TObject *ASender, 
    TStream *AStream) { 
    ftpCompletionStatus = 1; 
} 
// --------------------------------------------------------------------------- 

どれも今までに解雇されていません。なぜ彼らは発射しないだろうか?私のメインスレッドの同じ機能がうまくいきました。私はTIdFTPオブジェクトに実装したこれらのメソッドをどうにかしていないように感じていますが、その方法についてはわかりません。

ありがとうございます!

答えて

1

転送中に接続が失われると、Getメソッドが無期限にハングします。

最終的には失敗します。 OSが失われた接続を実際に検出してオープンソケットを無効にするにはしばらく時間がかかることがあります。そのため、I/O操作でエラーが報告されるようになります。長時間待たない場合は、ReadTimeoutプロパティを適切なタイムアウト(TIdFTPをデフォルトで1分に設定)とTransferTimeoutプロパティ(デフォルトでは無限)に設定してください。

アイデアは、接続がハングアップしているかどうかを検出し、スレッドを孤立させ、「再試行」を開始することです。

NEVER "orphan" a thread。代わりに、進行中の転送を終了してコマンドソケットを閉じるために、TIdFTPAbort()Disconnect()メソッドをメインスレッドに呼び出すことができます。

私の問題は、私は、スレッドのHファイル内のオブジェクトと同様に発射する必要があるメソッド(WorkBegin、WorkEnd、仕事、など)などが次の宣言したです....

は、同期されたメソッド内でApplication->ProcessMessages()とコールしないでください。このメソッドはすでにメインスレッドのメッセージハンドラの内部で実行されており、同期されたメソッドを終了するだけでメインのメッセージループに戻ります。

また、OnWork...ハンドラは、メインスレッドの外側から直接FrmFTP->FTPProg->Maxにアクセスしています。これらのアクセスも同期させる必要があります。 ANYTHINGメインUIに触れる必要があります。

Getの開始、転送、および完了時に、これらのメソッドは実行されません。なぜ彼らは発射しないだろうか?

最初に接続しましたか?おそらくFTPClntFTPThread::Execute()に作成されていますが、FTPClntを作成した後にハンドラをFTPClnt->OnWork...イベントに割り当てるのでしょうか?彼らは、例えば、あなたがそれを自分で行う必要があり、あなたのために自分自身をフックするつもりはないされています

FTPClnt = new TIdFTP; 
FTPClnt->OnWorkBegin = &FTPClntWorkBegin; 
FTPClnt->OnWorkEnd = &FTPClntWorkEnd; 
FTPClnt->OnWork = &FTPClntWork; 

私のメインスレッドで同じ機能がうまく働きました。

あなたは、デザイン時にフォーム上TIdFTPオブジェクトをドロップすると、オブジェクトインスペクタ内のOnWork...イベントを割り当てるとフォームが実行時に作成されたときに、その後、DFMストリーミングシステムはあなたのためのイベントハンドラをフックします。

イベントハンドラを宣言するだけでは不十分です。誰か(あなたかDFM)は、実行時にを実際にに接続しなければなりません。

+0

ありがとうございます。転送タイムアウトが5秒に設定されており、Getメソッドが返されることはありません。昨夜私の開発システムで一晩中吊り下げられ、Get呼び出しの後でコードの行を実行したことはありません。私のメインスレッドが永久に停止されないように、私はFTPソフトウェアをスレッドに入れなければならない理由を返すことはありません。 – martinarcher

+0

私は自分のメインフォームにTIdFTPオブジェクトを持っていて、オブジェクトインスペクタが私のためのイベントハンドラをフックアップしていたとは思っていました。サンプルコードをありがとう....私は私のスレッドにFTPClntが作成されているメソッドを実行する方法を追加します。 – martinarcher

+0

すべてのアクセスを同期させる必要があると言うと、フォームに触れるものをSyncronizeメソッドに移動する必要があるだけですか?再度、感謝します! – martinarcher

関連する問題