想到了通过FTP上传的方式完成异地备份。由于平时都是用PB做后台维护,PB功能专一,不容易完成这样的功能。听说DELPHI功能强大又易于上手,于是决定选择DELPHI7.
DELPHI的INDY组件有FTP的功能,于是翻阅了一下书籍,用INDY组件作了一个FTP上传的小程序,服务器端用SERV-U。做完后测试了一下,这个程序往FTP服务器上传输文件,文件夹,能覆盖以往的文件。有这三个功能就能满足我的要求了。于是我把它放到病历服务器上计划任务里,每天晚上定时启用。本以为这个事情就到此结束了,觉得开发FTP程序用一下INDY组件就可以了,没什么大不了的。但事实并非我想象的这么简单。而且好像随着探究的深入,问题也越来越麻烦。
第二天早上,我以为备份应该圆满结束,到病历服务器上一查看,没想到我的程序报了内存的错误,另外FTP服务器上只
接收了6个G的文件。我查看了一下我的代码,在遍历本地文件时,我采用了递归的方式。由于需要上传的文件和文件夹太多,
应该是堆栈溢出的问题引起的。于是我决定改用队列的方式来遍历本地文件。堆栈是先进后出,队列是先进先出,队列方式肯定不会出现溢出的问题。由堆栈的方式改为队列方式后,原本遍历路径时是一条路径访问到底再返回变成了层层的遍历。改好程序后,经过测试,OK,没问题,于是又把它放到了病历服务器上等其自动运行。
第二天早上,我到病历服务器上一查看,很好,程序圆满结束,没有报错,而且目标文件和源文件一致。我估计到这里我的程序应该算成功了,剩下的事情就是观测一下程序运行的稳定不稳定了。
第三天早上,一切正常,程序圆满完成任务。
第四天早上出现了异常,程序好像死掉了,任务没有完成。后续的几天里,任务有时能完成,有时不能完成。
我上网查了一下,发现有人说INDY组件不稳定。难道是INDY组件的原因,我想,或者直接用API函数的方式来做吧。于是,
我又修改了程序,放弃了INDY组件,改用API 函数。测试没问题,但是能不能根本解决问题我心里也没底。放到病历服务器上试一试,还是出现同样的问题:死掉。
为什么程序有时会死掉呢,会是网络问题吗。我测试了一下网络,网络没断点,但有时PING的时候延时稍长点,但FTP连接并没有中断,这点我肯定。难道是API函数本身的问题吗,FTP协议我不了解具体内容,即使了解FTP协议我一时也难以直接深入FTP协议来开发。会是连接病历服务器的客户端太多了吗?或许是FTP服务器端SERV-U的原因。我对问题的原因很茫然。网上搜索了一下,发现也有别人在做FTP上传或下载时出现死掉的问题,但是没有人给出解决的方案。
找不到问题症结,我只有退而找折衷的解决办法。我想用多线程的方式,在一个分线程里上传文件,如果分线程死掉了,就结束这个线程,重新生成一个线程,接着死掉的地方继续上传。如何判断线程死掉呢,我在另一个线程里设定一个时间变量,如果文件上传线程超过这个时间变量不返回我就认为线程死掉。我用TThread类来创建线程,用Terminate方法结束线程。实际运行了一下,还是有问题。Terminate方法并不能马上结束本线程,只是把terminated的值设为TRUE,如果要从外面把一个死掉的线程结束用Terminate方法是不行的.所以我发现在任务管理器里发现线程会越创建越多。
按照多线程的思路继续往下走,要想从外面立即结束线程,我没有找到别的好办法,只有用API函数来创建线程,然后需要结束线程是用terminatethread函数来从外面结束它。尽管在《WINDOWS核心编程》强调避免用terminatethread函数来结束线程,会造成资源泄露和一切未知问题。而且是terminatethread函数是异步的,即使返回值正确也不会立即结束线程,要和waitforsingleobject函数配合使用。目前我按照这个方法修改了程序后,出现的情况是:线程没有出现越来越多,程序没有死掉,但是依然不稳定,有时能完成任务,有时还没运行结束却出现莫名其妙退出程序的情况。
唉!依然没有最终搞定。
7 个解决方案
#1
程序里没有记录日志的功能吗?
加个记录日志功能这样也方便查找问题。
加个记录日志功能这样也方便查找问题。
#2
跟踪了一下,程序是在FTP服务器上执行创建文件夹的API函数或上传文件的API函数时卡死的,API函数卡死了,API函数没返回任何值。如果不用API函数,用INDY组件也是一样。
#3
这个问题彻底解决了。我的FTP服务器用的是SERV-U软件,可以查看日志。日志显示连接病历服务器端口失败。我的客户端程序用的是主动模式。FTP协议通讯时需要占用两个端口,一个是21端口,传输控制命令,另一个端口是用来传输文件,作为主动模式,FTP服务器端的20端主动连接客户端的一个随机端口,由于我的客户端也是一台服务器,连接了很多客户端,很多端口可能已被占用,而且我需要上传的文件和文件夹非常多,
我推测每执行一次上传命令服务器就要随机连接客户端一个端口,这样就可能和客户端被占用的端口发生了冲突。传输过程就会失败。
现在改为被动模式,由客户端去连接服务器端的一个随机端口。程序运行了一段日子相当稳定。
总结:所有问题总是有原因的,没有无缘无故的问题,之所以有莫名其妙的问题就是因为没找到问题的原因。
我推测每执行一次上传命令服务器就要随机连接客户端一个端口,这样就可能和客户端被占用的端口发生了冲突。传输过程就会失败。
现在改为被动模式,由客户端去连接服务器端的一个随机端口。程序运行了一段日子相当稳定。
总结:所有问题总是有原因的,没有无缘无故的问题,之所以有莫名其妙的问题就是因为没找到问题的原因。
#4
不错的总结,标记。。。。。
#5
Mark一下,以备后用
#6
学习了,我ftp 一直用被动模式,防止客户端防火墙当挡住了端口,不让服务器来连接
#7
感谢楼主做了精辟的结论.
#1
程序里没有记录日志的功能吗?
加个记录日志功能这样也方便查找问题。
加个记录日志功能这样也方便查找问题。
#2
跟踪了一下,程序是在FTP服务器上执行创建文件夹的API函数或上传文件的API函数时卡死的,API函数卡死了,API函数没返回任何值。如果不用API函数,用INDY组件也是一样。
#3
这个问题彻底解决了。我的FTP服务器用的是SERV-U软件,可以查看日志。日志显示连接病历服务器端口失败。我的客户端程序用的是主动模式。FTP协议通讯时需要占用两个端口,一个是21端口,传输控制命令,另一个端口是用来传输文件,作为主动模式,FTP服务器端的20端主动连接客户端的一个随机端口,由于我的客户端也是一台服务器,连接了很多客户端,很多端口可能已被占用,而且我需要上传的文件和文件夹非常多,
我推测每执行一次上传命令服务器就要随机连接客户端一个端口,这样就可能和客户端被占用的端口发生了冲突。传输过程就会失败。
现在改为被动模式,由客户端去连接服务器端的一个随机端口。程序运行了一段日子相当稳定。
总结:所有问题总是有原因的,没有无缘无故的问题,之所以有莫名其妙的问题就是因为没找到问题的原因。
我推测每执行一次上传命令服务器就要随机连接客户端一个端口,这样就可能和客户端被占用的端口发生了冲突。传输过程就会失败。
现在改为被动模式,由客户端去连接服务器端的一个随机端口。程序运行了一段日子相当稳定。
总结:所有问题总是有原因的,没有无缘无故的问题,之所以有莫名其妙的问题就是因为没找到问题的原因。
#4
不错的总结,标记。。。。。
#5
Mark一下,以备后用
#6
学习了,我ftp 一直用被动模式,防止客户端防火墙当挡住了端口,不让服务器来连接
#7
感谢楼主做了精辟的结论.