作者:Sim Ayers 翻译:刘建强R88(dEK
Win32 API 支持抢先式多线程网络,这是编写MFC网络蜘蛛非常有用的地方。SPIDER工程(程序)是一个如何用抢先式多线程技术实现在网上用网络蜘蛛/机器人聚集信息的程序。 DBu)xr}7A
该工程产生一个象蜘蛛一样行动的程序,该程序为断开的URL链接检查WEB站点。链接验证仅在href指定的链接上进行。它在一列表视图CListView中显示不断更新的URL列表,以反映超链接的状态。本工程能用作收集、索引信息的模板,该模板将这些信息存入到可以用于查询的数据库文件中。 mp&Le YYn
a -z23$3
搜索引擎在WEB上使用叫作Robots(也叫爬虫,蜘蛛,蠕虫,漫步者,滑行者等等)的程序收集信息,它从WEB上自动地聚集和索引信息,接着将这些信息存入数据库。(注意:一个机器人将搜索一个页面,然后把这个页面上的链接作为将要索引的新的URL的起点)用户可创建查询去查询这些数据库以发现他们需要的信息。 ROJ'-Vde9
n.Ur-ot
通过抢先式多线程地使用,你能索引一个基于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函数的线程参数。 ZaukMEq
wzNt c)~i
CSpiderThread* pThread; SU_] C+
pThread = NULL; 1OiZNuI:E
pThread = new CSpiderThread(CSpiderThread::ThreadFunc,pThreadParams); // 创建一个新的 CSpiderThread 对象; :o.x=c B
m>Z/ rqOK
在类CSpiderThread 构造函数中我们在线程参数中设置指针CWinThread* m_pThread ,于是我们可以指向这个线程正确的事例: /C ,>
pThreadParams->m_pThread = this; [c KI0
;)= z vr17
The CSpiderThread ThreadProc Function cDQw`ORP*g
%<ptkZK#
// 简单的工作线程函数 Cs1%g
UINT CSpiderThread::ThreadFunc(LPVOID pParam) ;@ll
{ #Zavdkw=d
ThreadParams * lpThreadParams = (ThreadParams*) pParam; H'= i
CSpiderThread* lpThread = (CSpiderThread*) lpThreadParams->m_pThread; e2h k
Ppb2"Ik
lpThread->ThreadRun(lpThreadParams); e~ 78'UH
k}0
// 这里使用SendMessage代替PostMessageUse,以保持当前线程数同步。 2,e|,N"zN
// 如果线程数大于 MAXIMUM_WAIT_OBJECTS (64), 本程序将变得不能响应用户输入 q}A3"$-F
cCbr-Z&
::SendMessage(lpThreadParams->m_hwndNotifyProgress, w*ktx{
WM_USER_THREAD_DONE, 0, (LPARAM)lpThreadParams); }]GK@nn7
// 删除lpThreadParams 和减少线程总数 __n"DLW
gV44PI6h
return 0; qhf/B)
} 5h^qtK
^a5~FI:
这个结构传递给CSpiderThread ThreadProc函数 |-Klh
typedef struct tagThreadParams (X'K)*G#
{ >'g60R[
HWND m_hwndNotifyProgress; ~2 ;y4%K
HWND m_hwndNotifyView; w5R9/<3 L
CWinThread* m_pThread; ~t$VzL1
CString m_pszURL; %tjEVQa
CString m_Contents; ' 7%9Sqx
CString m_strServerName; KJ |1zCM
CString m_strObject; Cr"hu;
CString m_checkURLName; f5eX%FR
CString m_string; U^S0H(>
DWORD m_dwServiceType; 0J B"@U&-
DWORD m_threadID; NiF*h~ q
DWORD m_Status; a7R7Ks|q
URLStatus m_pStatus; 4H)a7 <,
INTERNET_PORT m_nPort; Ex{]<6UAu
int m_type; "=)`*"rr
BOOL m_RootLinks; TOs|f8ay
Qoc-ZC"<6
}ThreadParams; DuaOi1Gw
u<[Y6m
CSpiderThread对象创建后,我们用CreatThread函数开始一个新的线程对象地执行。 BQ(`MM@
8V@3T/}
if (!pThread->CreateThread()) //开始一 CWinThread 对象地执行 V@F~Cx
{ ]Kd:ZmJ
AfxMessageBox("Cannot Start New Thread"); y3l sAe#
delete pThread; XWk^$"
pThread = NULL; 9G&l{7=
delete pThreadParams; M!,WU[mP
return FALSE; {' JoVJKv
} YOqBIbp~&)
一旦新的线程正在运行,我们使用::SengMessage函数发送消息到 CDocument’s-> CListView ,这个消息带有URL链接的状态结构。 8|gwH2 st~
if(pThreadParams->m_hwndNotifyView != NULL) XfharJ_b
::SendMessage(pThreadParams->m_hwndNotifyView,WM_USER_CHECK_DONE, 0, (LPARAM) &pThreadParams->m_pStatus); @#;2P'KL
Pi`}-GUe,
URL状态的结构: JHBX'1GQa
0@k)C z[0;
typedef struct tagURLStatus K_; '-B
{ e'Njl?>3
CString m_URL; u 6A!Sw
CString m_URLPage; ;hzm&My
CString m_StatusString; B*B}eXUph
CString m_LastModified; =r=?N/7I
CString m_ContentType; [ H|ifi
CString m_ContentLength; _e4%<!1
DWORD m_Status; QTe>EJ12
}URLStatus, * PURLStatus; 4rDa Jd>,
J)I|Xot
每个新的线程建立一个新的CMyInternetSession类(派生于CInternetSession)对象,并把 EnableStatusCallback设置为TRUE,于是,我们可以在所有的InternetSession回调时检查状态。将回调使用的dwContext ID设置为线程ID。 &GKtD)
pXap<T
BOOL CInetThread::InitServer() <&4 7W
{ QJ%[6S
D #Ku5~j
try Bj1{=Pvl
{ X}5}M+'~
m_pSession = new CMyInternetSession(AgentName,m_nThreadID); =k0qj_
int ntimeOut = 30; // 很重要!如果设置太小回引起服务器超时,如果设置太大则回引起线程挂起。 =[Z uE0c
/* 3U/| E
网络连接请求时间超时值在数毫秒级。如果连接请求时间超过这个超时值,请求将被取消。 9L+g;Js$4
缺省的超时值是无限的。 ;D>*Pzj
*/ -RK R. ,
m_pSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000* ntimeOut); " > ]{t[Ib
=Ul{#R z
/* 在重试连接之间的等待的延时值在毫秒级。*/ F15Yn
m_pSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000); !=SBeq
vOV$Hle
/* 在网络连接请求时的重试次数。如果一个连接企图在指定的重试次数后仍失败,则请求被取消。 缺省值为5。 */ ? j^:jV
m_pSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,1); lFT` WO
m_pSession->EnableStatusCallback(TRUE); 7%)KB4(/_
{$P')> /
} mi'3ibCG
catch (CInternetException* pEx) 9kby-A4
{ )Rc
// catch errors from WinINet /{%p%Q[X
//pEx->ReportError(); F1GFn|OA
m_pSession = NULL; q~6a$8+t
pEx->Delete(); =Ohro '
return FALSE ; moCr4*jDX,
} p>h}k_s
0lLg uBW@
return TRUE; d$B+xW
} OLE@35"v]
<,</ Ge
在一个单或多线程程序中使用MFC WinIne类,关键是要在所有MFC WinInet类函数周围使用try和catch块。因为互连网有时很不稳定,或者你访问的Web页面已不存在,则这种情况下,将抛出一个CInternetException错误。 9t+:L(*pK
!laOiH
xcX^L84/
try wpa^]l
{ MrhJk
// some MFC WinInet class function T#ehJq 5
} ,8+Jt@L
catch (CInternetException* pEx) VE*& t>I
{ z6'l" D'h
// catch errors from WinINet 0b+End#mp
//pEx->ReportError(); 0]2@T=*kTY
pEx->Delete(); <%=@Ue
return FALSE ; <26Jif:
} ItwJL`
最初线程数最大设置为64,你可以将它设置为从1到100的任何数。设置太高会使链接失败,意味着你将不得不重新检查URL链接。在/cgi-bin/目录下一个连续不断地迅猛地HTTP请求会使服务器崩溃。SPIDER 程序在1秒中发送四个HTTP请求,1分钟240个。这也将会使服务器崩溃。在任何服务器上你检查时放仔细一点。每个服务器都有一个请求Web文件的请求代理IP地址的日志。你或许会收到来自Web服务器管理员的龌龊的邮件。 9pq-"?vHY0
~k/GmH
7A4_b8
你可以为一些目录建立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。 eC*-/$D
AOR(1Qyo
创建: 4 X6_p(
Windows 95 7N I~47s|v
MFC/VC++ 5.0 0v'FE35~s
WinInet.h 时间 9/25/97 K*fh`Kz
WinInet.lib 时间 9/16/97 } 2P,Z6L
WinInet.dll 时间 9/18/97 >Mc,c(CvU
oJbMUEQQq
+-+%6O<C
问题: K84Ve Ae
i $:QOMA
允许 32,767 个URL 链接在 CListView 中。 c1L0#L/F6"
不能分析 URL的正确性 。 d2XS w>
|E#+X
>^5U XQr
资料: PH]/*LEj
Internet tools - Fred Forester c&AJFED]<
Multithreading Applications in Win32 ?@uyqi~:U
Win32 Multithreaded Programming -h?ed'e/zz
Win32 API 支持抢先式多线程网络,这是编写MFC网络蜘蛛非常有用的地方。SPIDER工程(程序)是一个如何用抢先式多线程技术实现在网上用网络蜘蛛/机器人聚集信息的程序。 DBu)xr}7A
该工程产生一个象蜘蛛一样行动的程序,该程序为断开的URL链接检查WEB站点。链接验证仅在href指定的链接上进行。它在一列表视图CListView中显示不断更新的URL列表,以反映超链接的状态。本工程能用作收集、索引信息的模板,该模板将这些信息存入到可以用于查询的数据库文件中。 mp&Le YYn
a -z23$3
搜索引擎在WEB上使用叫作Robots(也叫爬虫,蜘蛛,蠕虫,漫步者,滑行者等等)的程序收集信息,它从WEB上自动地聚集和索引信息,接着将这些信息存入数据库。(注意:一个机器人将搜索一个页面,然后把这个页面上的链接作为将要索引的新的URL的起点)用户可创建查询去查询这些数据库以发现他们需要的信息。 ROJ'-Vde9
n.Ur-ot
通过抢先式多线程地使用,你能索引一个基于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函数的线程参数。 ZaukMEq
wzNt c)~i
CSpiderThread* pThread; SU_] C+
pThread = NULL; 1OiZNuI:E
pThread = new CSpiderThread(CSpiderThread::ThreadFunc,pThreadParams); // 创建一个新的 CSpiderThread 对象; :o.x=c B
m>Z/ rqOK
在类CSpiderThread 构造函数中我们在线程参数中设置指针CWinThread* m_pThread ,于是我们可以指向这个线程正确的事例: /C ,>
pThreadParams->m_pThread = this; [c KI0
;)= z vr17
The CSpiderThread ThreadProc Function cDQw`ORP*g
%<ptkZK#
// 简单的工作线程函数 Cs1%g
UINT CSpiderThread::ThreadFunc(LPVOID pParam) ;@ll
{ #Zavdkw=d
ThreadParams * lpThreadParams = (ThreadParams*) pParam; H'= i
CSpiderThread* lpThread = (CSpiderThread*) lpThreadParams->m_pThread; e2h k
Ppb2"Ik
lpThread->ThreadRun(lpThreadParams); e~ 78'UH
k}0
// 这里使用SendMessage代替PostMessageUse,以保持当前线程数同步。 2,e|,N"zN
// 如果线程数大于 MAXIMUM_WAIT_OBJECTS (64), 本程序将变得不能响应用户输入 q}A3"$-F
cCbr-Z&
::SendMessage(lpThreadParams->m_hwndNotifyProgress, w*ktx{
WM_USER_THREAD_DONE, 0, (LPARAM)lpThreadParams); }]GK@nn7
// 删除lpThreadParams 和减少线程总数 __n"DLW
gV44PI6h
return 0; qhf/B)
} 5h^qtK
^a5~FI:
这个结构传递给CSpiderThread ThreadProc函数 |-Klh
typedef struct tagThreadParams (X'K)*G#
{ >'g60R[
HWND m_hwndNotifyProgress; ~2 ;y4%K
HWND m_hwndNotifyView; w5R9/<3 L
CWinThread* m_pThread; ~t$VzL1
CString m_pszURL; %tjEVQa
CString m_Contents; ' 7%9Sqx
CString m_strServerName; KJ |1zCM
CString m_strObject; Cr"hu;
CString m_checkURLName; f5eX%FR
CString m_string; U^S0H(>
DWORD m_dwServiceType; 0J B"@U&-
DWORD m_threadID; NiF*h~ q
DWORD m_Status; a7R7Ks|q
URLStatus m_pStatus; 4H)a7 <,
INTERNET_PORT m_nPort; Ex{]<6UAu
int m_type; "=)`*"rr
BOOL m_RootLinks; TOs|f8ay
Qoc-ZC"<6
}ThreadParams; DuaOi1Gw
u<[Y6m
CSpiderThread对象创建后,我们用CreatThread函数开始一个新的线程对象地执行。 BQ(`MM@
8V@3T/}
if (!pThread->CreateThread()) //开始一 CWinThread 对象地执行 V@F~Cx
{ ]Kd:ZmJ
AfxMessageBox("Cannot Start New Thread"); y3l sAe#
delete pThread; XWk^$"
pThread = NULL; 9G&l{7=
delete pThreadParams; M!,WU[mP
return FALSE; {' JoVJKv
} YOqBIbp~&)
一旦新的线程正在运行,我们使用::SengMessage函数发送消息到 CDocument’s-> CListView ,这个消息带有URL链接的状态结构。 8|gwH2 st~
if(pThreadParams->m_hwndNotifyView != NULL) XfharJ_b
::SendMessage(pThreadParams->m_hwndNotifyView,WM_USER_CHECK_DONE, 0, (LPARAM) &pThreadParams->m_pStatus); @#;2P'KL
Pi`}-GUe,
URL状态的结构: JHBX'1GQa
0@k)C z[0;
typedef struct tagURLStatus K_; '-B
{ e'Njl?>3
CString m_URL; u 6A!Sw
CString m_URLPage; ;hzm&My
CString m_StatusString; B*B}eXUph
CString m_LastModified; =r=?N/7I
CString m_ContentType; [ H|ifi
CString m_ContentLength; _e4%<!1
DWORD m_Status; QTe>EJ12
}URLStatus, * PURLStatus; 4rDa Jd>,
J)I|Xot
每个新的线程建立一个新的CMyInternetSession类(派生于CInternetSession)对象,并把 EnableStatusCallback设置为TRUE,于是,我们可以在所有的InternetSession回调时检查状态。将回调使用的dwContext ID设置为线程ID。 &GKtD)
pXap<T
BOOL CInetThread::InitServer() <&4 7W
{ QJ%[6S
D #Ku5~j
try Bj1{=Pvl
{ X}5}M+'~
m_pSession = new CMyInternetSession(AgentName,m_nThreadID); =k0qj_
int ntimeOut = 30; // 很重要!如果设置太小回引起服务器超时,如果设置太大则回引起线程挂起。 =[Z uE0c
/* 3U/| E
网络连接请求时间超时值在数毫秒级。如果连接请求时间超过这个超时值,请求将被取消。 9L+g;Js$4
缺省的超时值是无限的。 ;D>*Pzj
*/ -RK R. ,
m_pSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000* ntimeOut); " > ]{t[Ib
=Ul{#R z
/* 在重试连接之间的等待的延时值在毫秒级。*/ F15Yn
m_pSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000); !=SBeq
vOV$Hle
/* 在网络连接请求时的重试次数。如果一个连接企图在指定的重试次数后仍失败,则请求被取消。 缺省值为5。 */ ? j^:jV
m_pSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,1); lFT` WO
m_pSession->EnableStatusCallback(TRUE); 7%)KB4(/_
{$P')> /
} mi'3ibCG
catch (CInternetException* pEx) 9kby-A4
{ )Rc
// catch errors from WinINet /{%p%Q[X
//pEx->ReportError(); F1GFn|OA
m_pSession = NULL; q~6a$8+t
pEx->Delete(); =Ohro '
return FALSE ; moCr4*jDX,
} p>h}k_s
0lLg uBW@
return TRUE; d$B+xW
} OLE@35"v]
<,</ Ge
在一个单或多线程程序中使用MFC WinIne类,关键是要在所有MFC WinInet类函数周围使用try和catch块。因为互连网有时很不稳定,或者你访问的Web页面已不存在,则这种情况下,将抛出一个CInternetException错误。 9t+:L(*pK
!laOiH
xcX^L84/
try wpa^]l
{ MrhJk
// some MFC WinInet class function T#ehJq 5
} ,8+Jt@L
catch (CInternetException* pEx) VE*& t>I
{ z6'l" D'h
// catch errors from WinINet 0b+End#mp
//pEx->ReportError(); 0]2@T=*kTY
pEx->Delete(); <%=@Ue
return FALSE ; <26Jif:
} ItwJL`
最初线程数最大设置为64,你可以将它设置为从1到100的任何数。设置太高会使链接失败,意味着你将不得不重新检查URL链接。在/cgi-bin/目录下一个连续不断地迅猛地HTTP请求会使服务器崩溃。SPIDER 程序在1秒中发送四个HTTP请求,1分钟240个。这也将会使服务器崩溃。在任何服务器上你检查时放仔细一点。每个服务器都有一个请求Web文件的请求代理IP地址的日志。你或许会收到来自Web服务器管理员的龌龊的邮件。 9pq-"?vHY0
~k/GmH
7A4_b8
你可以为一些目录建立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。 eC*-/$D
AOR(1Qyo
创建: 4 X6_p(
Windows 95 7N I~47s|v
MFC/VC++ 5.0 0v'FE35~s
WinInet.h 时间 9/25/97 K*fh`Kz
WinInet.lib 时间 9/16/97 } 2P,Z6L
WinInet.dll 时间 9/18/97 >Mc,c(CvU
oJbMUEQQq
+-+%6O<C
问题: K84Ve Ae
i $:QOMA
允许 32,767 个URL 链接在 CListView 中。 c1L0#L/F6"
不能分析 URL的正确性 。 d2XS w>
|E#+X
>^5U XQr
资料: PH]/*LEj
Internet tools - Fred Forester c&AJFED]<
Multithreading Applications in Win32 ?@uyqi~:U
Win32 Multithreaded Programming -h?ed'e/zz

1275

被折叠的 条评论
为什么被折叠?



