VFP 结束进程 !

yrt888 2008-06-13 01:59:13
我是用这种方法来结束进程的: RUN /N TASKKILL /F /PID 进程ID

现在想问一下,在VFP下有没有同等功效(强制性)的方法呢?谢谢各位大侠!
...全文
187 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
yrt888 2008-06-14
  • 打赏
  • 举报
回复
冰刃果然厉害,开着禁止新进程,不小程序出错!
yrt888 2008-06-13
  • 打赏
  • 举报
回复
是啊,我也知道我的那种方法很方便,不过我现在尝试先打开冰刃,启用冰刃的防止创建新进程的功能来浏览网页,有时候上了一些有问题的网页,系统内存或虚拟内存会迅速消耗,这是我的小程序就使用我的上述办法,来结束马桶浏览器,现在想了一想,我的方法是利用DOS的,会不会冰刃不让我执行了,若是程序内部的命令就应该可以执行的!
十豆三 2008-06-13
  • 打赏
  • 举报
回复
Declare Integer WinExec in kernel32 string, integer
MyCommand="TASKKILL /F /PID "+进程ID
= WinExec (MyCommand,0)
Clear Dlls

这样就不会有Command窗口了。
yrt888 2008-06-13
  • 打赏
  • 举报
回复
正在尝试!。。。
十豆三 2008-06-13
  • 打赏
  • 举报
回复
所以你的方法最简单。
十豆三 2008-06-13
  • 打赏
  • 举报
回复
VFP中如何结束(系统)进程?

*-----------------------------------------

参考文章:
http://www.onlyred.com/computer/system/windows/200512/96.html

-----------------------------------------------------------------

方法一:可以结束除System、SMSS.EXE和CSRSS.EXE外所有进程

******只有System、SMSS.EXE和CSRSS.EXE不能结束。前两个是纯内核态的,最后那个是Win32子系统

Exit_ProFileName='sqlservr.exe' && sqlservr.exe为要结束的系统进程名称
IF GetAllProcessID('Process_CurTable')
SELECT Pth32ProcessID INTO ARRAY Exit_id FROM Process_CurTable WHERE ALLTRIM(UPPER(PszExeFile))=UPPER(Exit_ProFileName)
lcString='RUN /N7 ntsd -c q -p '+ALLTRIM(STR(Exit_id))
&lcString
ENDIF

* -------------------------------------
* 枚举当前所有进程
* -------------------------------------
FUNCTION GetAllProcessID ( lpProcTable )
lpProcTable = IIF(PARAMETERS()=1 AND TYPE([lpProcTable])=[C], lpProcTable, [AllProclists] )
DECLARE INTEGER CreateToolhelp32Snapshot IN kernel32 INTEGER lFlags, INTEGER lProcessID
DECLARE INTEGER Process32First IN kernel32 INTEGER hSnapShot, STRING @PROCESSENTRY32_uProcess
DECLARE INTEGER Process32Next IN kernel32 INTEGER hSnapShot, STRING @PROCESSENTRY32_uProcess
DECLARE INTEGER CloseHandle IN kernel32 INTEGER hObject
DECLARE INTEGER GetLastError IN kernel32

CREA CURSOR (lpProcTable) (PdwSize N(3), PcntUsage N(12), ;
Pth32ProcessID N(12), Pth32DefaultHeapID N(12), ;
Pth32ModuleID N(12), PcntThreads N(12), ;
Pth32ParentProcessID N(12), PpcPriClassBase N(3), ;
PdwFlags N(3), PszExeFile C(254) )
lnHand = 0
lnHand = CreateToolhelp32Snapshot(3,0)
IF lnHand>0
dwSize = Num2Dword(296)
cntUsage = Num2Dword(0)
th32ProcessID = Num2Dword(0)
th32DefaultHeapID = Num2Dword(0)
th32ModuleID = Num2Dword(0)
cntThreads = Num2Dword(0)
th32ParentProcessID = Num2Dword(0)
pcPriClassBase = Num2Dword(0)
dwFlags = Num2Dword(0)
szExeFile = REPLI(CHR(0), 260)
lcTitle = dwSize + cntUsage + th32ProcessID + th32DefaultHeapID ;
+ th32ModuleID + cntThreads + th32ParentProcessID ;
+ pcPriClassBase + dwFlags + szExeFile
IF Process32First(lnHand,@lcTitle) > 0 && 第一个进程是 kernel32.dll,没必要列出
DO WHILE Process32Next(lnHand,@lcTitle)> 0
INSERT INTO (lpProcTable) (PdwSize, PcntUsage, Pth32ProcessID, Pth32DefaultHeapID, ;
Pth32ModuleID, PcntThreads, Pth32ParentProcessID, ;
PpcPriClassBase, PdwFlags, PszExeFile) ;
VALUES ( ;
Dword2Num(SUBSTR(lcTitle, 1,4)), ;
Dword2Num(SUBSTR(lcTitle, 5,4)), ;
Dword2Num(SUBSTR(lcTitle, 9,4)), ;
Dword2Num(SUBSTR(lcTitle,13,4)), ;
Dword2Num(SUBSTR(lcTitle,17,4)), ;
Dword2Num(SUBSTR(lcTitle,21,4)), ;
Dword2Num(SUBSTR(lcTitle,25,4)), ;
Dword2Num(SUBSTR(lcTitle,29,4)), ;
Dword2Num(SUBSTR(lcTitle,33,4)), ;
SUBSTR(SUBSTR(lcTitle, 37), 1, AT(CHR(0),SUBSTR(lcTitle, 37))-1) )
ENDDO
ENDIF
= CloseHandle(lnHand)
RETURN .T.
ELSE
RETURN .F.
ENDIF
ENDFUNC

FUNCTION Num2Dword ( lpnNum )
DECLARE INTEGER RtlMoveMemory IN kernel32 AS RtlCopyDword STRING @pDeststring, INTEGER @pVoidSource, INTEGER nLength
lcDword = SPACE(4)
= RtlCopyDword(@lcDword, BITOR(lpnNum,0), 4)
RETURN lcDword
ENDFUNC

FUNCTION Dword2Num ( tcDword )
DECLARE INTEGER RtlMoveMemory IN kernel32 AS RtlCopyNum INTEGER @DestNumeric, STRING @pVoidSource, INTEGER nLength
lnNum = 0
=RtlCopyNum(@lnNum, tcDword, 8)
RETURN lnNum
ENDFUNC






-----------------------------------------------------------------

方法二:可以结束非系统进程

Exit_ProFileName='QQ.exe' && QQ.exe为要结束的系统进程名称
IF GetAllProcessID('Process_CurTable')
SELECT Pth32ProcessID INTO ARRAY Exit_id FROM Process_CurTable WHERE ALLTRIM(UPPER(PszExeFile))=UPPER(Exit_ProFileName)
IF ExitProcessId(Exit_id)
MESSAGEBOX('结束进程成功!',64,'信息提示')
ELSE
MESSAGEBOX('结束进程失败!',16,'信息提示')
ENDIF
ENDIF

* -------------------------------------
* 枚举当前所有进程
* -------------------------------------
FUNCTION GetAllProcessID ( lpProcTable )
lpProcTable = IIF(PARAMETERS()=1 AND TYPE([lpProcTable])=[C], lpProcTable, [AllProclists] )
DECLARE INTEGER CreateToolhelp32Snapshot IN kernel32 INTEGER lFlags, INTEGER lProcessID
DECLARE INTEGER Process32First IN kernel32 INTEGER hSnapShot, STRING @PROCESSENTRY32_uProcess
DECLARE INTEGER Process32Next IN kernel32 INTEGER hSnapShot, STRING @PROCESSENTRY32_uProcess
DECLARE INTEGER CloseHandle IN kernel32 INTEGER hObject
DECLARE INTEGER GetLastError IN kernel32

CREA CURSOR (lpProcTable) (PdwSize N(3), PcntUsage N(12), ;
Pth32ProcessID N(12), Pth32DefaultHeapID N(12), ;
Pth32ModuleID N(12), PcntThreads N(12), ;
Pth32ParentProcessID N(12), PpcPriClassBase N(3), ;
PdwFlags N(3), PszExeFile C(254) )
lnHand = 0
lnHand = CreateToolhelp32Snapshot(3,0)
IF lnHand>0
dwSize = Num2Dword(296)
cntUsage = Num2Dword(0)
th32ProcessID = Num2Dword(0)
th32DefaultHeapID = Num2Dword(0)
th32ModuleID = Num2Dword(0)
cntThreads = Num2Dword(0)
th32ParentProcessID = Num2Dword(0)
pcPriClassBase = Num2Dword(0)
dwFlags = Num2Dword(0)
szExeFile = REPLI(CHR(0), 260)
lcTitle = dwSize + cntUsage + th32ProcessID + th32DefaultHeapID ;
+ th32ModuleID + cntThreads + th32ParentProcessID ;
+ pcPriClassBase + dwFlags + szExeFile
IF Process32First(lnHand,@lcTitle) > 0 && 第一个进程是 kernel32.dll,没必要列出
DO WHILE Process32Next(lnHand,@lcTitle)> 0
INSERT INTO (lpProcTable) (PdwSize, PcntUsage, Pth32ProcessID, Pth32DefaultHeapID, ;
Pth32ModuleID, PcntThreads, Pth32ParentProcessID, ;
PpcPriClassBase, PdwFlags, PszExeFile) ;
VALUES ( ;
Dword2Num(SUBSTR(lcTitle, 1,4)), ;
Dword2Num(SUBSTR(lcTitle, 5,4)), ;
Dword2Num(SUBSTR(lcTitle, 9,4)), ;
Dword2Num(SUBSTR(lcTitle,13,4)), ;
Dword2Num(SUBSTR(lcTitle,17,4)), ;
Dword2Num(SUBSTR(lcTitle,21,4)), ;
Dword2Num(SUBSTR(lcTitle,25,4)), ;
Dword2Num(SUBSTR(lcTitle,29,4)), ;
Dword2Num(SUBSTR(lcTitle,33,4)), ;
SUBSTR(SUBSTR(lcTitle, 37), 1, AT(CHR(0),SUBSTR(lcTitle, 37))-1) )
ENDDO
ENDIF
= CloseHandle(lnHand)
RETURN .T.
ELSE
RETURN .F.
ENDIF
ENDFUNC

FUNCTION Num2Dword ( lpnNum )
DECLARE INTEGER RtlMoveMemory IN kernel32 AS RtlCopyDword STRING @pDeststring, INTEGER @pVoidSource, INTEGER nLength
lcDword = SPACE(4)
= RtlCopyDword(@lcDword, BITOR(lpnNum,0), 4)
RETURN lcDword
ENDFUNC

FUNCTION Dword2Num ( tcDword )
DECLARE INTEGER RtlMoveMemory IN kernel32 AS RtlCopyNum INTEGER @DestNumeric, STRING @pVoidSource, INTEGER nLength
lnNum = 0
=RtlCopyNum(@lnNum, tcDword, 8)
RETURN lnNum
ENDFUNC

* -------------------------------------
* 从 ProcessId 关闭进程
* -------------------------------------
FUNCTION ExitProcessId ( lpnProcessId )
DECLARE INTEGER TerminateProcess IN kernel32 INTEGER hProcess , INTEGER uExitCode
DECLARE INTEGER OpenProcess IN kernel32 INTEGER dwDesiredAccess, INTEGER binheritHandle, INTEGER dwProcessId
DECLARE INTEGER GetCurrentProcessId IN kernel32
IF lpnProcessId = GetCurrentProcessId()
RETURN .F.
ELSE
hproc = OpenProcess(2035711, 0, lpnProcessId) && 从进程 ID 获得进程句柄
IF hproc = 0
RETURN .F.
ELSE
= TerminateProcess(hproc, 0) && 关闭进程
RETURN .T.
ENDIF
ENDIF
ENDFUNC
十豆三 2008-06-13
  • 打赏
  • 举报
回复
VFP本身没有,需要用到API
此文件是MyFll.fll文件不可分割的一部分,包含对MyFll函数库全部说明及示例。 MyFll是专为Microsoft Visual FoxPro设计的扩展库,部分函数来自任明汉(RMH myF1论坛)前辈提供的myDll代码翻译而成,由于很多功能利用VFP处理比较烦锁,或无法实现,使用此库可有效解决VFP的弱项。部分与Win32Api同名的函数,是Win32API的封装。部分函数取自网上开源算法,在相关函数中均有注明。 此源代码使用VC6 sp6开发,采用VFP9 Sp2的库文件,理论上可以应用于VFP6 7 8 9版本。 此库在第一次打开时自动添加智能感应功能已关闭。请在打开后,使用FllAddFoxCode()向智能感应库添加所有的函数原型(需要VFP7以上),此库存所有函数使用VFP推荐的命名规则,一般可以根据函数名和知能感应的提示参数来推测参数及返回值。 开发环境可以使用FllHelp()函数来检查函数信息: 取得此版本函数个数:FllHelp() 取得第x个函数的信息:?FllHelp(x) 显示提示信息:?FllHelp(x,.T.) 显示指定函数的信息:FllHelp("SendMessage",.T.) 显示Fll的版:?FllGetVersion() 添加智能感应代码:FllAddFoxCode() 版本信息:由于不定期更新,请及时核对版本(右键属性),版本为X.X.X.X,第一位为主版本号,第二位为函数个数,第三位为发布的年份,第四位为日期。当前版本为:1.179.9.811 版权:你可以自由使用、散发此函数库及此帮助,包括应用于你的商业软件中。在转发时应注意帮助文件于函数库和帮助同在。不得对软件进行破解、反编译等破性或逆向工程。MyFll作者不承担可能由于技术原因或失误给你带来的错误或损失。发现错误可以与作者取得联系共同改进。 感谢:我的帮助论坛http://www.myf1.net/bbs 梅子论坛 http://www.meizvfp.com/bbs 感谢:各位为Myfll做测试、编写帮助的热心网友。 作者:木瓜 ljyit@163.com 函数列表: 硬件相关函数: GetDiskSerial        读取指定硬盘的序列号 GetCpuId           读取CPU的序列号 GetMAC            读取网卡的MAC地址 GetVolumeNumber       读取指写磁盘的卷标 IsDiskInDrive        检查指定磁盘是否就绪 GetPort           读取系统的串口、并口 ComOpen           打开串口 ComWrite           向串口输出信息 ComRead            从串口读取信息 ComClose           关闭串口 GetGUID            获取全球唯一ID AEthernet          枚举网卡的所有信息 加密解密函数: MD5File           计算一个文件的MD5效验和 MD5String          计算一个字符串的MD5效验和 CRC32File          计算一个文件的CRC32效验和 CRC32String         计算一个字符串的CRC32效验和 des             采用DES算法加密或解密一个字符串,长度为8位 des16            采用DES算法加密或解密一个字符串,长度为16位 des24            采用DES算法加密或解密一个字符串,长度为24位 EnDeString          双向加密解密字符串的函数 Encrypt           双向加密解密字符串 RSACalc           RSA计算函数 RSAGen            生成随机RSA密钥函数 RSACmp            比较两个十六进制值是否相等 URLEncode          URL编码 URLDecode          URL解码 QPEncode           Quoted-Printable QP编码 QPDecode           Quoted-Printable QP解码 压缩解压函数: Zip              压缩文件 UnZip             解压文件 UnZipFile           解压单个文件           ZipInfo            测试一个文件是否在压缩文件中存在 ZipFileToStr         将压缩文件中的文件解压到变量 ZipAFile           将zip文件中的文件信息生成的数组 CompressString        压缩一个字符串 DeCompressString       解压字符串 数据库: CursorToStr         将Cursor生成变量 ChangesToStr         将Cursor的变动情况生成变量         StrToCursor         将变量还原为Cursor AppendFromStr        将变量中的表追加到指定表中 ACursorList         将变量中的表信息生成数组 ACursorFields        将变量中的指定表的字段信息生成数组 CRC32Record         计算一条记录的CRC32值 SQLCallBack         SQL回调函数载入 SQLCallReset         SQL回调函数卸载 PackMDB           压缩修复Access数据库 ReadMemo           读取vfp中大于16M的备注字段 网络相关函数: DownFile           从internet上下载文件到本地 DownFileX           线程方式从网上下载一个文件 HttpGetFileSize       读取internet上的文件大小 HttpPostData         向http服务器Post数据 HttpOpen           打开一个Internet句柄 HttpAddParms         为Http句柄添加一个参数 HttpSend           发送Http句柄中的Post数据 HttpClose          关闭Http句柄 FtpDownFile          从FTP服务器下载文件 FtpUploadFile        向FTP服务器上传文件 FtpConnect          连接FTP服务器 FtpDisconnect        断开FTP服务器连接 FtpAFile          枚举Ftp中的所有文件 FtpCreateDir        在FTP服务器上创建一个文件夹         FtpSetCurrentDir      设置当前的文件夹 FtpDeleteDir        删除FTP服务器上的文件夹 FtpDelFile         删除FTP服务器上的文件 FtpRename          重命名FTP服务器上的文件 FtpFOpen          打开FTP服务器上的文件 FtpFClose         关闭FTP服务器上的文件 FtpFRead          读取FTP服务器上的文件 FtpFWrite          写入FTP服务器上的文件 FtpSetPasv          设置FTP被动工作模式 ShareAdd           在局域网共享文件夹 ShareDel           删除共享文件夹的共享 ShareMapDrive         映射网络驱动器 ShareDelDrive         删除映射的网络驱动器 GetLocalIP          读取本机IP DomainToIP          转换域名为IP地址 DialUp            建立拨号连接 DialDown           断开拨号连接 GetSqlServer         列出所有网络上的SQL Server IpToMAC           根据IP得到MAC地址 邮件函数: SmtpCreate          创建一个SMTP发送邮件的句柄 SmtpNewMail         在内存中创建邮件内容,等待发送 SmtpSend           发送邮件 SmtpGetLastError       检测邮件最后的错误 Pop3Create          创建一个POP3接收邮件的句柄 Pop3Close          关闭句柄 Pop3AMailList        枚举POP3服务器上的邮件数量 Pop3DeleteMail        删除POP3邮件服务器上的邮件 Pop3GetMail         下载一封邮件 Pop3GetMailHeader      下载邮件头 Pop3DeleteMail        删除服务器上的邮件 打印相关函数: PaperAdd           添加自定义纸张并返回ID PaperDel           删除自定义纸张 PaperInfo          读取所有纸张信息或指定纸张信息 APaper            枚举所有纸张生成数组 GetDefaultPrinter      取得默认打印机的名称 SetDefaultPrinter      设置默认打印机 PrinterOpen         启用一个打印任务 PrinterOutPage        打印页对像 PrinterClose         结束打印 常用转换函数: ToPY             生成指写字符串的拼音首字 NToC             数字转人民币大写 hzbh             计算指定字符串的汉字笔划 StringToDword        将高底位存放的字符串,转换为字符型 DwordToString        将整型数值转换为字符型数值 NumConver          进制转换函数,能够将一个数字转换为2至36进制的字符串 ConverNum           将指定进制的字符串转换为数值型 GB2312ToBIG5         简体转繁体 BIG5ToGB2312         繁体转简体 FormToBmp          将表单保存为BMP图片 RectToBmp           指定屏幕区域保存为bmp图片 StrReverse          指定屏幕区域保存为bmp图片 ImageConver         转换图片格式 FTrim            删除字符串中除指定字符以外的字符 Thumbnail          缩放图片 注册表读写函数: regRead           读取注册表中的设置 regWrite           向注册表中写入设置 regDelKey          删除注册表中的分支 regDelValue         删除注册表中的设置 ini文件读写函数: iniRead           从ini文件中读取设置 iniWrite           向ini文件中写入一个设置 iniSet            设置默认的数据段和ini文件 iniSetSection        设置默认的数据段 iniSetFileName        设置默认的ini文件 系统托盘 SysTrayAdd          向系统托盘添加一个图标 SysTrayEdit         修改系统托盘的图标 SysTrayDel          删除系统托盘中的图标 HotKeyAdd          向系统注册一个热键 HotKeyDel          删除向系统注册的热键 SysTrayShowMessage      显示托盘消息 文件操作 CopyFiles          复制文件 MoveFiles          移动文件 DeleteFiles         删除文件 CreateShortcut        创建快捷方式 GetIcon           释放exe或dll中的图标 其它: SetVFPEvents         设置MYFLL内部函数回调功能 SetDateTime         设置Windows系统时间 ChangEres          更改屏幕的分辨率 idleLoad           开始加载空闲检测 idleSeconds         读取系统空闲时间 idleUnload          卸载空闲检测 KillApp           终止指定进程 KillAllApp          终止所有进程,但排除指定标题的进程 KillProcessByName      根据程序文件名杀死一个进程 FindAllFile         查找指定文件夹下的所有文件 IsNum            检测函数是否是数字 CheckProcess         检测主程序是否重复运行 ProcLoad            载入一个VFP函数,取得函数地址 ProcUnload          卸载函数 MemRead           读取指定地址的内存 MemWrite           写入指写内存 PushError          系统错误处理压栈 PopError           系统错误处理出栈 Format            格式化输出字符串(类C语言) CreateLink          创建文件关联 DesktopHide         隐藏桌面 SystemKeySet         禁用系统键 RegisterFile         注册文件名解除文件注册 封装过的Win32 API函数: FindWindow          查找指定窗口的句柄 SendMessage         向指写窗口发送指定消息 PostMessage         将消息投递到指定句柄的消息队列 ShowWindow          显示指定窗口 ShowWindowAsync       显示指定窗口 SetWindowLong        设置窗口的扩展样式 SetLayeredWindowAttributes  设置窗口效果 SetForegroundWindow     激活指定窗口使这成为最前面的窗口 ShellExecute         调用系统关联,打开一个文件 ShellExecWait        调用一个程序,并等待执行结束 SuspendThread        暂停一个线程 ResumeThread         恢复一个线程 Beep             使电脑内喇叭发出beep声 ExitWindowsEx        退出Windows Sleep            程序挂起nMilliseconds毫秒 ExitProcess         终止当前进程 GetLastError         返回最后的错误号码 SetParent          设置窗口的父窗口 UpdateWindow         更新窗口
在《爬虫/蜘蛛程序的制作(C#语言)》一文中,已经介绍了爬虫程序实现的基本方法,可以说,已经实现了爬虫的功能。只是它存在一个效率问题,下载速度可能很慢。这是两方面的原因造成的: 1. 分析和下载不能同步进行。在《爬虫/蜘蛛程序的制作(C#语言)》中已经介绍了爬虫程序的两个步骤:分析和下载。在单线程的程序中,两者是无法同时进行的。也就是说,分析时会造成网络空闲,分析的时间越长,下载的效率越低。反之也是一样,下载时无法同时进行分析,只有停下下载后才能进行下一步的分析。问题浮出水面,我想大家都会想到:把分析和下载用不同的线程进行,问题不就解决了吗? 2. 只是单线程下载。相信大家都有用过网际快车等下载资源的经历,它里面是可以设置线程数的(近年版本默认是10,曾经默认是5)。它会将文件分成与线程数相同的部分,然后每个线程下载自己的那一部分,这样下载效率就有可能提高。相信大家都有加多线程数,提升下载效率的经历。但细心的用户会发现,在带宽一定的情况下,并不是线程越多,速度越快,而是在某一点达到峰值。爬虫作为特殊的下载工具,不具备多线程的能力何以有效率可谈?爬虫在信息时代的目的,难道不是快速获取信息吗?所以,爬虫需要有多线程(可控数量)同时下载网页。 好了,认识、分析完问题,就是解决问题了: 多线程在C#中并不难实现。它有一个命名空间:System.Threading,提供了多线程的支持。 要开启一个新线程,需要以下的初始化: ThreadStart startDownload = new ThreadStart( DownLoad ); //线程起始设置:即每个线程都执行DownLoad(),注意:DownLoad()必须为不带有参数的方法 Thread downloadThread = new Thread( startDownload ); //实例化要开启的新类 downloadThread.Start();//开启线程 由于线程起始时启动的方法不能带有参数,这就为多线程共享资源添加了麻烦。不过我们可以用类级变量(当然也可以使用其它方法,笔者认为此方法最简单易用)来解决这个问题。知道开启多线程下载的方法后,大家可能会产生几个疑问: 1. 如何控制线程的数量? 2. 如何防止多线程下载同一网页? 3. 如何判断线程结束? 4. 如何控制线程结束? 下面就这几个问题提出解决方法: 1. 线程数量我们可以通过for循环来实现,就如同当年初学编程的打点程序一样。 比如已知用户指定了n(它是一个int型变量)个线程吧,可以用如下方法开启五个线程 Thread[] downloadThread;//声名下载线程,这是C#的优势,即数组初始化时,不需要指定其长度,可以在使用时才指定。这个声名应为类级,这样也就为其它方法控件它们提供了可能 ThreadStart startDownload = new ThreadStart( DownLoad );//线程起始设置:即每个线程都执行DownLoad() downloadThread = new Thread[ n ];//为线程申请资源,确定线程总数 for( int i = 0; i < n; i++ )//开启指定数量的线程数 { downloadThread[i] = new Thread( startDownload );//指定线程起始设置 downloadThread[i].Start();//逐个开启线程 } 好了,实现控制开启线程数是不是很简单啊? 2. 下面出现的一个问题:所有的线程都调用DonwLoad()方法,这样如何避免它们同时下载同一个网页呢? 这个问题也好解决,只要建立一下Url地址表,表中的每个地址只允许被一个线程申请即可。具体实现: 可以利用数据库,建立一个表,表中有四列,其中一列专门用于存储Url地址,另外两列分别存放地址对应的线程以及该地址被申请的次数,最后一列存放下载的内容。(当然,对应线程一列不是必要的)。当有线程申请后,将对应线程一列设定为当前线程编号,并将是否申请过一列设置为申请一次,这样,别的线程就无法申请该页。如果下载成功,则将内容存入内容列。如果不成功,内容列仍为空,作为是否再次下载的依据之一,如果反复不成功,则进程将于达到重试次数(对应该地址被申请的次数,用户可设)后,申请下一个Url地址。主要的代码如下(以VFP为例): CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I ) &&建立一个表ctablename.dbf,含有地址、文本内容、已经尝试下载次数、线程标志(初值为-1,线程标志是从0开始的整数)四个字段 cfullname = (ctablename) + '.dbf'&&为表添加扩展名 USE (cfullname) GO TOP LOCATE FOR (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND ( threadNum = thisNum OR threadNum = - 1) ) &&查找尚未下载成功且应下载的属于本线程权限的Url地址,thisNum是当前线程的编号,可以通过参数传递得到 gotUrl = curl recNum = RECNO() IF recNum <= RECCOUNT() THEN &&如果在列表中找到这样的Url地址 UPDATE (cfullname) SET ldowned = ( ldowned + 1 ) , threadNum = thisNum WHERE RECNO() = recNum &&更新表,将此记录更新为已申请,即下载次数加1,线程标志列设为本线程的编号。 cfulltablename = (ctablename) + '.dbf' USE (cfulltablename) SET EXACT ON LOCATE FOR curl = (csiteurl) &&csiteurl是参数,为下载到的内容所对应的Url地址 recNumNow = RECNO()&&得到含有此地址的记录号 UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() = recNumNow &&插入对应地址的对应内容 ctablename = (ctablename) + '.dbf' USE (ctablename) GO TOP SET EXACT ON LOCATE FOR curl = (cnewurl) &&查找有无此地址 IF RECNO() > RECCOUNT() THEN &&如果尚无此地址 SET CARRY OFF INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum ) VALUES ( (cnewurl) , "" , 0 , -1 ) &&将主页地址添加到列表 好了,这样就解决了多线程中,线程冲突。当然,去重问题也可以在C#语言内解决,只根建立一个临时文件(文本就可以),保存所有的Url地址,差对它们设置相应的属性即可,但查找效率可能不及数据库快。 3. 线程结束是很难判断的,因为它总是在查找新的链接。用者认为可以假设:线程重复N次以后还是没有能申请到新的Url地址,那么可以认为它已经下载完了所有链接。主要代码如下: string url = ""; int times = 0; while ( url == "" )//如果没有找到符合条件的记录,则不断地寻找符合条件的记录 { url = getUrl.GetAUrl( …… );//调用GetAUrl方法,试图得到一个url值 if ( url == "" )//如果没有找到 { times ++;//尝试次数自增 continue; //进行下一次尝试 } if ( times > N ) //如果已经尝试够了次数,则退出进程 { downloadThread[i].Abort; //退出进程 } else//如果没有尝试够次数 { Times = 0; //尝试次数归零处理 } //进行下一步针对得到的Url的处理 } 4. 这个问题相对简单,因为在问题一中已经建议,将线程声名为类级数组,这样就很易于控制。只要用一个for循环即可结束。代码如下: for( int i = 0; i < n; i++ )//关闭指定数量n的线程数 { downloadThread[i].Abort();//逐个关闭线程 } 好了,一个蜘蛛程序就这样完成了,在C#面前,它的实现原来如此简单。 这里笔者还想提醒读者:笔者只是提供了一个思路及一个可以实现的解决方案,但它并不是最佳的,即使这个方案本身,也有好多可以改进的地方,留给读者思考。 最后说明一下我所使用的环境: winXP sp2 Pro VFP 9.0 Visual Studio 2003 .net中文企业版 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/peter1_jiang/archive/2007/10/23/1839137.aspx

2,723

社区成员

发帖
与我相关
我的任务
社区描述
VFP,是Microsoft公司推出的数据库开发软件,用它来开发数据库,既简单又方便。
社区管理员
  • VFP社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧