抢先式多线程网络蜘蛛
作者:Sim Ayers 翻译:刘建强
Win32 API 支持抢先式多线程网络,这是编写MFC网络蜘蛛非常有用的地方。SPIDER工程(程序)是一个如何用抢先式多线程技术实现在网上用网络蜘蛛/机器人聚集信息的程序。
该工程产生一个象蜘蛛一样行动的程序,该程序为断开的URL链接检查WEB站点。链接验证仅在href指定的链接上进行。它在一列表视图CListView中显示不断更新的URL列表,以反映超链接的状态。本工程能用作收集、索引信息的模板,该模板将这些信息存入到可以用于查询的数据库文件中。
搜索引擎在WEB上使用叫作Robots(也叫爬虫,蜘蛛,蠕虫,漫步者,滑行者等等)的程序收集信息,它从WEB上自动地聚集和索引信息,接着将这些信息存入数据库。(注意:一个机器人将搜索一个页面,然后把这个页面上的链接作为将要索引的新的URL的起点)用户可创建查询去查询这些数据库以发现他们需要的信息。
通过抢先式多线程地使用,你能索引一个基于URL链接的WEB页面,启动一个新的线程跟随每个新的URL链接,索引一个新的URL起点。本工程使用和自定义的MDI子框架一起使用的MDI 文档类,在下载WEB页面时显示一个编辑视图,在检查URL连接时显示一个列表视图。另外,本工程使用了CObArray,CInternetSession,CHttpConnection,ChttpFile和CWinThread MFC类。CWinThread类用于产生多线程来代替在CInternetSession类中的异步模式,这种模式是从insock的16位windows平台保留下来的。SPIDER工程使用简单的工作线程去检查URL链接,或者下载一个Web页面。CSpiderThread类是从CWinThread类中派生的,所以,每个CSpiderThread对象可以使用CWinThread 的MESSAGE_MAP()函数。通过在CSpiderThread类中声明"DECLARE_MESSAGE_MAP()",用户接口可以响应用户的输入。这意味着你可以在一个Web服务器上检查URL链接的同时,你可以从另一个Web服务器上下载或打开一个Web页面。只有在线程数超过定义为64的MAXIMUM_WAIT_OBJECTS时,用户接口将不会响应用户的输入。在每个CSpiderThread对象的构造函数中,我们提供了ThreadProc函数以及将传送到ThreadProc函数的线程参数。
CSpiderThread* pThread;
pThread = NULL;
pThread = new CSpiderThread(CSpiderThread::ThreadFunc,pThreadParams); // 创建一个新的 CSpiderThread 对象;
在类CSpiderThread 构造函数中我们在线程参数中设置指针CWinThread* m_pThread ,于是我们可以指向这个线程正确的事例:
pThreadParams->m_pThread = this;
The CSpiderThread ThreadProc Function
// 简单的工作线程函数
UINT CSpiderThread::ThreadFunc(LPVOID pParam)
{
ThreadParams * lpThreadParams = (ThreadParams*) pParam;
CSpiderThread* lpThread = (CSpiderThread*) lpThreadParams->m_pThread;
lpThread->ThreadRun(lpThreadParams);
// 这里使用SendMessage代替PostMessageUse,以保持当前线程数同步。
// 如果线程数大于 MAXIMUM_WAIT_OBJECTS (64), 本程序将变得不能响应用户输入
::SendMessage(lpThreadParams->m_hwndNotifyProgress,
WM_USER_THREAD_DONE, 0, (LPARAM)lpThreadParams);
// 删除lpThreadParams 和减少线程总数
return 0;
}
这个结构传递给CSpiderThread ThreadProc函数
typedef struct tagThreadParams
{
HWND m_hwndNotifyProgress;
HWND m_hwndNotifyView;
CWinThread* m_pThread;
CString m_pszURL;
CString m_Contents;
CString m_strServerName;
CString m_strObject;
CString m_checkURLName;
CString m_string;
DWORD m_dwServiceType;
DWORD m_threadID;
DWORD m_Status;
URLStatus m_pStatus;
INTERNET_PORT m_nPort;
int m_type;
BOOL m_RootLinks;
}ThreadParams;
CSpiderThread对象创建后,我们用CreatThread函数开始一个新的线程对象地执行。






