搶先式多線程網絡蜘蛛
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函數開始一個新的線程對象地執行。
if (!pThread->CreateThread()) //開始一 CWinThread 對象地執行
{
AfxMessageBox("Cannot Start New Thread");
delete pThread;
pThread = NULL;
delete pThreadParams;
return FALSE;
}
一旦新的線程正在運行,我們使用::SengMessage函數發送消息到 CDocument's-> CListView ,這個消息帶有URL鏈接的狀態結構。
if(pThreadParams->m_hwndNotifyView != NULL)
::SendMessage(pThreadParams->m_hwndNotifyView,WM_USER_CHECK_DONE, 0, (LPARAM) &pThreadParams->m_pStatus);
URL狀態的結構:
typedef struct tagURLStatus
{
CString m_URL;
CString m_URLPage;
CString m_StatusString;
CString m_LastModified;
CString m_ContentType;
CString m_ContentLength;
DWORD m_Status;
}URLStatus, * PURLStatus;
每個新的線程建立一個新的CMyInternetSession類(派生于CInternetSession)對象,并把 EnableStatusCallback設置為TRUE,于是,我們可以在所有的InternetSession回調時檢查狀態。將回調使用的dwContext ID設置為線程ID。
BOOL CInetThread::InitServer()
{
try
{
m_pSession = new CMyInternetSession(AgentName,m_nThreadID);
int ntimeOut = 30; // 很重要!如果設置太小回引起服務器超時,如果設置太大則回引起線程掛起。
/*
網絡連接請求時間超時值在數毫秒級。如果連接請求時間超過這個超時值,請求將被取消。
缺省的超時值是無限的。
*/
m_pSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000* ntimeOut);
/* 在重試連接之間的等待的延時值在毫秒級。*/
m_pSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000);
/* 在網絡連接請求時的重試次數。如果一個連接企圖在指定的重試次數后仍失敗,則請求被取消。 缺省值為5。 */
m_pSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,1);
m_pSession->EnableStatusCallback(TRUE);
}
catch (CInternetException* pEx)
{
// catch errors from WinINet
//pEx->ReportError();
m_pSession = NULL;
pEx->Delete();
return FALSE ;
}
return TRUE;
}
在一個單或多線程程序中使用MFC WinIne類,關鍵是要在所有MFC WinInet類函數周圍使用try和catch塊。因為互連網有時很不穩定,或者你訪問的Web頁面已不存在,則這種情況下,將拋出一個CInternetException錯誤。
try
{
// some MFC WinInet class function
}
catch (CInternetException* pEx)
{
// catch errors from WinINet
//pEx->ReportError();
pEx->Delete();
return FALSE ;
}
最初線程數最大設置為64,你可以將它設置為從1到100的任何數。設置太高會使鏈接失敗,意味著你將不得不重新檢查URL鏈接。在/cgi-bin/目錄下一個連續不斷地迅猛地HTTP請求會使服務器崩潰。SPIDER 程序在1秒中發送四個HTTP請求,1分鐘240個。這也將會使服務器崩潰。在任何服務器上你檢查時放仔細一點。每個服務器都有一個請求Web文件的請求代理IP地址的日志。你或許會收到來自Web服務器管理員的齷齪的郵件。
你可以為一些目錄建立robots.txt 文件來防止這些目錄被索引。這個機制通常用于保護/cgi-bin/ 目錄。CGI腳本占用更多的要檢索的服務器資源。當SPIDER程序檢查URL鏈接時,它的目標是不太快地請求太多的文檔。SPIDER程序堅持機器人拒絕的標準。這個標準是機器人開發者之間的協議,允許WWW站點限制URL上的機器人的請求。通過使用這個限制訪問的標準,機器人將不檢索Web服務器希望拒絕的任何文檔。在檢查根URL前,程序檢查看是否有robots.txt文件在主目錄下。如果SPIDER程序發現robots.txt文件,將放棄搜索。另外,程序也檢查所有Web頁面中的META標記。如果發現一個META標記,它的NAME="ROBOTS" CONTENT ="NOINDEX,NOFOLLOW",則不索引那個頁面上的URL。
創建:
Windows 95
MFC/VC++ 5.0
WinInet.h 時間 9/25/97
WinInet.lib 時間 9/16/97
WinInet.dll 時間 9/18/97
來源:月光博客