我有一个用Embarcadero的C ++ 10 Seattle编写的VCL应用程序。主线程产生一个线程来运行TIdFTP功能,因为如果在传输过程中连接丢失,Get方法将无限期挂起。我的想法是检测连接是否挂起,孤立线程,并产生“重试”。我的问题是我已经在线程的h文件中声明了对象以及应该触发的方法(WorkBegin,WorkEnd,Work等),如下所示....
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);
};
然后我在线程的cpp文件中实现了Work函数,就像这样......
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;
}
// ---------------------------------------------------------------------------
在Get开始,传输和完成时,这些方法都没有被触发。知道他们为什么不开火?我的主线程上的相同功能工作正常。我觉得我不知道我在TIdFTP对象上实现了这些方法,但我不知道如何去做。
谢谢!
答案 0 :(得分:1)
如果在传输过程中连接丢失,则Get方法会无限期挂起。
最终应该失败。操作系统可能需要一段时间才能实际检测到丢失的连接并使打开的套接字无效,因此I / O操作会开始报告错误。如果您不想等待那么久,请确保将ReadTimeout
属性设置为合理的超时(TIdFTP
默认设置为1分钟),以及TransferTimeout
属性(默认为无限)。
想法是检测连接是否挂起,孤立线程,并产生“重试”。
从不“孤儿”一个帖子。您可以简单地让主线程调用TIdFTP
的{{1}}和Abort()
方法来终止正在进行的传输并分别关闭命令套接字。
我的问题是我已经在线程的h文件中声明了对象以及应该触发的方法(WorkBegin,WorkEnd,Work等),如下所示....
不要在同步方法中调用Disconnect()
。该方法已在主线程消息处理程序内运行,只需退出同步方法,以便控制返回主消息循环。
此外,您的Application->ProcessMessages()
处理程序正在从主线程外部直接访问OnWork...
。这些访问也需要同步。触摸主UI的 ANYTHING 需要同步。
在Get开始,传输和完成时,这些方法都没有被触发。知道他们为什么不开火吗?
你开始时把它们连接起来了吗?据推测FrmFTP->FTPProg->Max
正在FTPClnt
中创建FTPThread::Execute()
,但是在创建FTPClnt->OnWork...
后是否将处理程序分配给FTPClnt
个事件?他们不会为你做好准备,你必须亲自去做,例如:
FTPClnt = new TIdFTP;
FTPClnt->OnWorkBegin = &FTPClntWorkBegin;
FTPClnt->OnWorkEnd = &FTPClntWorkEnd;
FTPClnt->OnWork = &FTPClntWork;
我主线程上的相同功能运行良好。
如果您在设计时在表单上删除TIdFTP
对象,并在Object Inspector中分配其OnWork...
个事件,那么DFM流式处理系统会在表单时为您挂起事件处理程序是在运行时创建的。
仅仅声明事件处理程序是不够的。有人(你或DFM)必须在运行时将它们连接起来。