<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[互利多商家交互平台 http://huliduo.com]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[]]></description>
<link>http://hi.baidu.com/yueqiangsh</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[wininet.dll函数库：不会过期的cookie]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/f7281b50656e4264853524a7.html]]></link>
        <description><![CDATA[
		
		<p>wininet.dll中包含很多win32下和网络有关的函数,包括internet,ftp等，下面演示一个IE下不过期的cookie。 比如csdn的登陆信息可以保存2个星期，你在登陆后把系统时间改为2周后，登陆信息就失效了,使用InternetSetCookie可以自己设置过期日期。 首先在IE中登陆，登陆时选择信息保存2周，然后运行如下代码，运行之后你可以把日期调整到2010年看效果：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools"><a href="http://blog.csdn.net/jinjazz/archive/2008/07/11/2638952.aspx#">view plain</a><a href="http://blog.csdn.net/jinjazz/archive/2008/07/11/2638952.aspx#">copy to clipboard</a><a href="http://blog.csdn.net/jinjazz/archive/2008/07/11/2638952.aspx#">print</a><a href="http://blog.csdn.net/jinjazz/archive/2008/07/11/2638952.aspx#">?</a></div>
</div>
<ol class="dp-c">
    <li class="alt"><span><span class="keyword">using</span><span> System; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">using</span><span> System.Text; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">using</span><span> System.Runtime.InteropServices; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span class="keyword">namespace</span><span> ConsoleApplication1 &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">class</span><span> Program &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/// &lt;summary&gt; </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/// 设置cookie </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/// &lt;/summary&gt; </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport(</span><span class="string">&quot;wininet.dll&quot;</span><span>, CharSet = CharSet.Auto, SetLastError = </span><span class="keyword">true</span><span>)] &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">extern</span><span> </span><span class="keyword">bool</span><span> InternetSetCookie(</span><span class="keyword">string</span><span> lpszUrlName, </span><span class="keyword">string</span><span> lbszCookieName, </span><span class="keyword">string</span><span> lpszCookieData); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/// &lt;summary&gt; </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/// 获取cookie </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/// &lt;/summary&gt; </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport(</span><span class="string">&quot;wininet.dll&quot;</span><span>, CharSet = CharSet.Auto, SetLastError = </span><span class="keyword">true</span><span>)] &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">extern</span><span> </span><span class="keyword">bool</span><span> InternetGetCookie( &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">string</span><span> url, </span><span class="keyword">string</span><span> name, StringBuilder data, </span><span class="keyword">ref</span><span> </span><span class="keyword">int</span><span> dataSize); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> Main(</span><span class="keyword">string</span><span>[] args) &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//获取旧的 </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuilder cookie = </span><span class="keyword">new</span><span> StringBuilder(</span><span class="keyword">new</span><span> String(</span><span class="string">' '</span><span>,2048)); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span> datasize = cookie.Length; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">bool</span><span> b= InternetGetCookie(</span><span class="string">&quot;http://community.csdn.net&quot;</span><span>, </span><span class="keyword">null</span><span>, cookie, </span><span class="keyword">ref</span><span> datasize); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//删除旧的 </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">foreach</span><span> (</span><span class="keyword">string</span><span> fileName </span><span class="keyword">in</span><span> System.IO.Directory.GetFiles(System.Environment.GetFolderPath(Environment.SpecialFolder.Cookies))) &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span> (fileName.ToLower().IndexOf(</span><span class="string">&quot;csdn&quot;</span><span>) &gt; 0) &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.IO.File.Delete(</span><span class="string">&quot;csdn&quot;</span><span>); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//生成新的 </span><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">foreach</span><span> (</span><span class="keyword">string</span><span> c </span><span class="keyword">in</span><span> cookie.ToString().Split(</span><span class="string">';'</span><span>)) &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">string</span><span>[] item = c.Split(</span><span class="string">'='</span><span>); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">string</span><span> name = item[0]; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">string</span><span> value = item[1] + </span><span class="string">&quot;;expires=Sun,22-Feb-2099 00:00:00 GMT&quot;</span><span>; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InternetSetCookie(</span><span class="string">&quot;http://community.csdn.net&quot;</span><span>,name,value); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InternetSetCookie(</span><span class="string">&quot;http://forum.csdn.net&quot;</span><span>, name, value); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InternetSetCookie(</span><span class="string">&quot;http://webim.csdn.net&quot;</span><span>, name, value); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/c%23">c#</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/f7281b50656e4264853524a7.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-11  17:56</pubDate>
        <category><![CDATA[c#]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/f7281b50656e4264853524a7.html</guid>
</item>

<item>
        <title><![CDATA[复杂背景的验证码识别破解，以Discuz的动画验证码为例]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/4223074419a38f4a510ffe17.html]]></link>
        <description><![CDATA[
		
		<div class="entry">
<p>对于比较复杂的验证码，比如DZ论坛最新的验证码，处理起来相对麻烦一些，但是原理还是和普通的识别一样的，无非多了个背景处理的方案，看如下对DZ论坛的验证码的识别的思路</p>
<p>//power by www.crazycoder.cn</p>
<p><img class="alignnone size-full wp-image-36" title="test1" height="60" src="http://www.crazycoder.cn/WebFiles/20088/9bb25c6a-d23d-4d7e-8c80-40208d21d6b6.png" width="150"></p>
<p>首先我们要去除它的背景，对于这样稍微复杂的背景，用过去的方法很难做到，上图的例子还不是很明显，我发现很多图片背景色和字母色近似，而且字母颜色是不断变化的，背景也是不断变化的</p>
<p><img class="alignnone size-medium wp-image-37" title="87ew-1771021430" height="60" src="http://www.crazycoder.cn/WebFiles/20088/52392d77-0772-4507-9d54-280190ee1d5b.png" width="150"><img class="alignnone size-medium wp-image-38" title="3tft-1071601132" height="60" src="http://www.crazycoder.cn/WebFiles/20088/7c18a910-987f-446d-a7fe-285045a5fe01.png" width="150"><img class="alignnone size-medium wp-image-39" title="7hbg-1528746287" height="60" src="http://www.crazycoder.cn/WebFiles/20088/8b3fa0d7-b75e-4530-8151-f63b36291a66.png" width="150"><img class="alignnone size-medium wp-image-40" title="8p3f-2085326489" height="60" src="http://www.crazycoder.cn/WebFiles/20088/be306654-5f8a-4b65-8b59-8c53c3c25c87.png" width="150"><img class="alignnone size-medium wp-image-41" title="9x4x-1309785358" height="60" src="http://www.crazycoder.cn/WebFiles/20088/7ee38c1d-2a6e-46e8-90a7-6aa530d82a3f.png" width="150"></p>
<p>那我初始的想法是找到图片中使用颜色最多的方法，于是我们用HSL表示各点颜色，接着进行统计，得到最大的几个峰值，这里便是图片中几个最丰富的颜色的L值得累加值</p>
<p><img class="alignnone size-medium wp-image-42" title="四个峰值分别代表4个突出的颜色" height="148" src="http://www.crazycoder.cn/WebFiles/20088/d1d93e62-de55-4c94-adaf-874f78486c64.png" width="253"></p>
<p>其余的都可以认为是噪音，我们对每个峰值进行分割，得到如下图片</p>
<p><img class="alignnone size-medium wp-image-43" title="颜色分割后的图片" height="260" src="http://www.crazycoder.cn/WebFiles/20088/cadcb921-13d2-4c73-bebb-984fa2285e27.png" width="160"></p>
<p>你看这样就把单个颜色图片分割出来了，接下来就是找到图片中除去黑色和白色后的图片</p>
<p><img class="alignnone size-medium wp-image-44" title="hsl2" height="258" src="http://www.crazycoder.cn/WebFiles/20088/dca4e442-5484-4ecd-8459-005cbbf95515.png" width="157"></p>
<p>然后进行灰化处理，阀值处理，降噪，得到</p>
<p><img class="alignnone size-medium wp-image-45" title="hsl3" height="251" src="http://www.crazycoder.cn/WebFiles/20088/55741060-4f54-4d72-88ad-a1ddbd67f2e7.png" width="150"></p>
<p>接着根据边界检测出来的最左侧x位置，来排序字母顺序</p>
<p><img class="alignnone size-medium wp-image-46" title="hsl4" height="123" src="http://www.crazycoder.cn/WebFiles/20088/0c648cf3-3a64-45b4-818e-5df514090cbd.png" width="33"></p>
<p>接下来的事情就轻车熟路了，把图片转成标准模板，通过少量学习就达到了95%以上的识别率</p>
<p>c:15 j:8 8:7 t:9 9:4 x:7 4:6 2:4 h:7 f:8 e:18 b:5 y:3 k:4 w:3 g:5 3:5 7:6 r:2 m:3 q:4 v:2 p:3 6:2<br>
以上数据表示 c学习15次 j学习8次…</p>
<p><img class="alignnone size-full wp-image-47" title="hsl5" height="670" src="http://www.crazycoder.cn/WebFiles/20088/ad664f1c-186f-4f0f-8d96-9ca45efb02b8.png" width="365"></p>
<p>只要字符不粘连，大部分验证码干扰技术都是可以有办法，所以为什么google验证码看起来很简单，但是没有人能够很好的破解它得原因。</p>
<p>补充，<br>
rise在留言中发现有一些字符加入杂点的问题，由于这种验证码不是很普遍，稍微做了研究<br>
<img class="alignnone size-full wp-image-66" title="有杂点的字符" height="60" src="http://www.crazycoder.cn/WebFiles/20088/989b0a98-db70-4641-87fd-414ac096fc42.png" width="150"></p>
<p>CY3E 这个图片3字中有杂点，其他没有，按照文章中介绍的办法，怎么知道这个3不是像其他颜色杂点一样的图片呢？<br>
<img class="alignnone size-full wp-image-65" title="字符中杂点1" height="112" src="http://www.crazycoder.cn/WebFiles/20088/476e611a-2105-4f7b-b167-8f38eb7f368f.png" width="499"><br>
我觉得需要加入一个步骤，就是对每次过滤颜色生成出来的图片，进行填充<br>
找到3的杂点原图：<br>
<img class="alignnone size-full wp-image-67" title="3的杂点提出了" height="60" src="http://www.crazycoder.cn/WebFiles/20088/0fdcf868-dda9-4ea6-b460-cff6e66f680a.png" width="150"><br>
然后我们进行算法填充<br>
<img class="alignnone size-full wp-image-68" title="填充之后的3" src="http://www.crazycoder.cn/WebFiles/20088/b640af2d-cc7a-4de0-b6c0-d048a384f94f.bmp"></p>
<p>这个图片与其他全部是杂点的图片之间的差别进行过滤，我考虑可以通过以下方法：<br>
1、连贯点的宽度<br>
2、连贯点的个数<br>
这样剩下的就只剩下CY3E的过滤后的图片</p>
<p>至于字符倾斜的问题，我觉得完全可以在机器学习过程中，我们自己旋转正在学习的图片一定角度，例如从-10到+10度，只不过这样的学习库会大一些，但是就10个数字的验证码来说，这点性能损失应该可以忽略不计。</p>
</div> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/c%23">c#</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/4223074419a38f4a510ffe17.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-10  15:40</pubDate>
        <category><![CDATA[c#]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/4223074419a38f4a510ffe17.html</guid>
</item>

<item>
        <title><![CDATA[验证码识别，最新Discuz验证码和PhpWind验证码的识别]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/e508172b5c5fa0fce6cd400b.html]]></link>
        <description><![CDATA[
		
		<p>需验证码识别，对常用论坛的验证码识别的时候大家用来做群发是最合适不过了。一个非常有意义的参考</p>
<p>注：非crazycoder原装，文章是转载的，原文出处不祥了，很多地方都有，找不到原出处了</p>
<p>验证码(captcha)是伴随自动提交程序(spam)的出现而出现的。现在各种论坛、博客、投票等程序都带有验证码功能。大部分验证码都比较容 易识别，只需要简单对照一下特征码就可以得到百分之百准确的结果。也有稍微复杂一点的，比如phpwind和discuz的验证码。</p>
<p>前段时间做了phpwind和discuz的验证码识别，phpwind6.0以前的验证码和discuz最新的验证码如果在不改变后台验证码配置的情况下，识别正确率几乎可以达到100%，现在跟大家分享一下识别方法。</p>
<p>验证码识别一般分为以下几个步骤：</p>
<ol>
    <li>取出字模</li>
    <li>二值化</li>
    <li>计算特征</li>
    <li>对照样本</li>
</ol>
<p>各种验证码在具体的步骤上操作会有所不同。</p>
<p>我的程序是用VC++写的，这里不贴详细代码了，只讲识别方法。</p>
<p><img src="http://www.crazycoder.cn/WebFiles/20088/1db6919b-18fb-4ac3-a0ea-c3e569c3c280.jpg"></p>
<p>先说phpwind验证码的识别方法：</p>
<p>具体分为这几步：</p>
<ol>
    <li>把图片横向等宽分为4块</li>
    <li>找出每块图片中分布最多的一种颜色</li>
    <li>与已有样本比较得出结果</li>
</ol>
<p>因为这个验证码的字符分布几乎是等宽的，所以我们首先把图片切为4份，这样方便取出每一个字符。分成4块后，通过每一块中的颜色值对比可以很快得到 字符的特征。因为每一块中字符的颜色值比杂点颜色值要多很多，而且字符是纯色的，所以只要统计出最多的一种颜色，然后去除其它颜色就可以得到只有字符的干 净图片。然后对图片二值化（即构造一个二维数组对应图片上有颜色的点，把有颜色的点的数组值置为1，无颜色的置为0），与样本比对即可得到字符。当然首先 要得到样本。样本的制作与上面分析的步骤一致。经过测试，上面这种方法的识别率是100%的，不会有差错。</p>
<p><img src="http://www.crazycoder.cn/WebFiles/20088/a17aa90c-af6f-4d57-8a24-77cfbd7e2dbe.jpg"></p>
<p>discuz的验证码识别较之phpwind要稍难一点。因为图片带有不太容易去掉的背景。字符也不是单纯的字符，有阴影边框，而且不等宽，位置不确定。我们具体分为以下几步：</p>
<ol>
    <li>去除背景色</li>
    <li>分出每一个字符区域</li>
    <li>用轮廓法（berg）得到特征码</li>
    <li>与样本比较得出结果</li>
</ol>
<p>这个背景色是渐变的而字符的颜色是不变的。首先去除对角线上找不到相同颜色的点，然后统计出每一种颜色占用的区域的宽度和高度。去除占用区域高度小 于图片总高度1/5或大于图片总高度2/3的点，因为一个字符不可能达到这种尺寸。再去除密度（即颜色点数/颜色所占的区域宽高的积）小于15%的点。剩 下的就只有干净的字符的颜色点了。</p>
<p><img src="http://www.crazycoder.cn/WebFiles/20088/65f8a284-ed2a-4867-8272-65eb9ced807f.jpg"></p>
<p>把这些点分为4份。（分割的办法为从左到右用一条竖直的线扫描，扫描线经过的连续区域就是字符区域。）分成4个字符块后，我们就可以对每一个字符块进行轮廓特征取值。</p>
<p>什么是轮廓法？我是由berg（berg是网易社区的牛人，对我帮助不少）那里获知验证码识别中的轮廓法。即将一个字模点阵，以四条直线由上下左右 4个方向向字符中心扫描，遇到点即停下，把每一条线通过的路径长度记下。然后以比路径长度和其它一些相关的参数得到正确的字符。</p>
<p>我稍微变换了一下轮廓法。即把4个方向上的路径长度变为波的形式。波峰记为1，波谷记为0，最后得到一个由1和0组成的特征串，与样本串比较即可得 到匹配结果。有几个字符，如V和Y、H和M、4和6等，得到的特征串可能是一样的，这样需要通过其它的一些参数来辅助得到结果。</p>
<p><font face="Verdana">下面是我计算的特征串和字符的对照样本：</font><br>
<font face="Verdana">10-10-10-10- X <br>
1-1010-1-10101- W <br>
-1010--- W <br>
1--1-101- T <br>
-1-1010-10- R <br>
--10-10- R <br>
101-101-1010-1010- Q <br>
-1-101-1- P <br>
--1-1- P <br>
-10--1010- M <br>
-10-10-10- K <br>
10-10-1-1- J <br>
10-10--- J <br>
101-101-1010-10- G <br>
--101-1- F <br>
--1010-- E <br>
101-101-10101-101- C <br>
101-10-10-10- C <br>
-1-10101-1- B <br>
---- B <br>
10101-101-101-101- 9 <br>
1---10- 9 <br>
-101--- 8 <br>
10--1-101- 7 <br>
-1-10-- 6 <br>
1-101-10-101- 4 <br>
1010---- 3 <br>
1010-101-1010-- 2 <br>
10--10-- 2 <br>
//below is equivocal<br>
1-10-1-101- V  //Y<br>
10-10-10-- G  //Q<br>
-10--10- H  //M<br>
10101-101-10101-101- 3  //8<br>
101-101-101-101- 4  //6</font></p>
<p> </p>
<p>上面这种方法，对discuz的默认验证码，即如图所示的验证码识别正确率为100%</p>
<p> </p>
<p>上面对phpwind和discuz的验证码识别方法均没有用到高级的算法，更加没有用到人工智能的知识，不免有点遗憾，不过准确率相当高，也容易看懂。</p>
<p>在实际应用中可能遇到一些问题，比如discuz验证码可以在后台设为gif图片格式。如何把gif动画中那一个字符帧转为bmp图片呢？下面是VC里面的方法：</p>
<p><font face="Verdana">BOOL CCaptchaBreak::Gif2Bmp(CString &amp;sPath)<br>
{<br>
 ULONG_PTR&nbsp;&nbsp;  GdippToken;&nbsp;&nbsp;  <br>
 GdiplusStartupInput&nbsp;&nbsp;  GdippStart;&nbsp;&nbsp;  <br>
 GdiplusStartup(&amp;GdippToken,&amp;GdippStart,0);<br>
 BSTR bsTemp = sPath.AllocSysString();<br>
 Bitmap&nbsp;&nbsp;  bmp(bsTemp);<br>
 ::SysFreeString(bsTemp);</font></p>
<p><font face="Verdana"> int&nbsp;&nbsp;  FrameCount,FramePos,size,pause;&nbsp;&nbsp;  <br>
 PropertyItem*&nbsp;&nbsp;  pPropItem;&nbsp;&nbsp;  <br>
 GUID&nbsp;&nbsp;  pageGuid;&nbsp;&nbsp;  <br>
 GUID*&nbsp;&nbsp;  pDimID;&nbsp;&nbsp;  <br>
 UINT&nbsp;&nbsp;  count;&nbsp;&nbsp;  </font></p>
<p><font face="Verdana"> count=bmp.GetFrameDimensionsCount();&nbsp;&nbsp;  </font></p>
<p><font face="Verdana"> pDimID=new GUID[count];&nbsp;&nbsp;  </font></p>
<p><font face="Verdana"> bmp.GetFrameDimensionsList(pDimID,count);&nbsp;&nbsp;  <br>
 FrameCount=bmp.GetFrameCount(&amp;pDimID[0]);</font></p>
<p><font face="Verdana"> if (1==FrameCount) //if is bmp then exit<br>
 {<br>
&nbsp;&nbsp; delete[]pDimID;&nbsp;&nbsp;  <br>
&nbsp;&nbsp; return FALSE;<br>
 }</font></p>
<p><font face="Verdana"> size=bmp.GetPropertyItemSize(PropertyTagFrameDelay);&nbsp;&nbsp;  <br>
 pPropItem=(PropertyItem*)malloc(size);&nbsp;&nbsp;  </font></p>
<p><font face="Verdana"> bmp.GetPropertyItem(PropertyTagFrameDelay,size,pPropItem);&nbsp;&nbsp;  <br>
 delete[]pDimID;&nbsp;&nbsp;  </font></p>
<p><font face="Verdana"> pageGuid=FrameDimensionTime;&nbsp;&nbsp;  <br>
 FramePos=0; </font></p>
<p><font face="Verdana"> int iFontFramePos = 0;<br>
 int iMaxPause = 0;<br>
 while (FramePos</font></p>
<p><font face="Verdana"> return TRUE;<br>
}</font></p>
<p><font face="Verdana">BOOL CCaptchaBreak::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)<br>
{<br>
 UINT  num = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // number of image encoders<br>
 UINT  size = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // size of the image encoder array in bytes</font></p>
<p><font face="Verdana"> ImageCodecInfo* pImageCodecInfo = NULL;</font></p>
<p><font face="Verdana"> GetImageEncodersSize(&amp;num, &amp;size);<br>
 if(size == 0)<br>
&nbsp;&nbsp; return FALSE;  </font></p>
<p><font face="Verdana"> pImageCodecInfo = (ImageCodecInfo*)(malloc(size));<br>
 if(pImageCodecInfo == NULL)<br>
&nbsp;&nbsp; return FALSE;  </font></p>
<p><font face="Verdana"> GetImageEncoders(num, size, pImageCodecInfo);</font></p>
<p><font face="Verdana"> for(UINT j = 0; j &lt; num; ++j)<br>
 {<br>
&nbsp;&nbsp; if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; *pClsid = pImageCodecInfo[j].Clsid;<br>
&nbsp;&nbsp;&nbsp; free(pImageCodecInfo);<br>
&nbsp;&nbsp;&nbsp; return TRUE;  // Success<br>
&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;  <br>
 }</font></p>
<p><font face="Verdana"> free(pImageCodecInfo);<br>
 return FALSE;  <br>
}</font></p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/c%23">c#</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/e508172b5c5fa0fce6cd400b.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-10  15:34</pubDate>
        <category><![CDATA[c#]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/e508172b5c5fa0fce6cd400b.html</guid>
</item>

<item>
        <title><![CDATA[ajax验证用户名是否存在]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/abcd67114fa291c3a7ef3f00.html]]></link>
        <description><![CDATA[
		
		<p>LoginValidate.aspx</p>
<p>&lt;%@ Page Language=&quot;C#&quot; AutoEventWireup=&quot;true&quot; CodeFile=&quot;LoginValidate.aspx.cs&quot; Inherits=&quot;Admin_LoginValidate&quot; %&gt;</p>
<p>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><font color="#1d4944">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</font></a>&quot;&gt;<br>
&lt;html xmlns=&quot;<a href="http://www.w3.org/1999/xhtml"><font color="#1d4944">http://www.w3.org/1999/xhtml</font></a>&quot;&gt;<br>
&lt;head runat=&quot;server&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;  &lt;title&gt;验证用户名是否存在&lt;/title&gt;</p>
<p>&nbsp;&nbsp;&nbsp;  &lt;script type=&quot;text/javascript&quot;&gt;<br>
var xmlHttp;<br>
function createXMLHttpRequest()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(window.ActiveXObject)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  xmlHttp = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else if(window.XMLHttpRequest)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  xmlHttp = new XMLHttpRequest();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
}<br>
//处理方法<br>
function CheckUserName()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  createXMLHttpRequest();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  var url= &quot;../ashx/LoginValidate.ashx?username=&quot;+document.getElementById(&quot;username&quot;).value;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  xmlHttp.open(&quot;GET&quot;,url,true);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  xmlHttp.onreadystatechange=ShowResult;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  xmlHttp.send(null);<br>
&nbsp;&nbsp;&nbsp;&nbsp;  // document.getElementById(&quot;Msg&quot;).innerHTML='';<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
}<br>
//回调方法<br>
function ShowResult()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(xmlHttp.readyState==4) <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (xmlHttp.status == 200)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  alert(&quot;Server is done!&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  alert(xmlHttp.responseText);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  document.getElementById(&quot;Msg&quot;).innerHTML=xmlHttp.responseText;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else if (xmlHttp.status == 404)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  alert(&quot;Request URL does not exist&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else if (xmlHttp.status == 403) <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  alert(&quot;Access&nbsp;&nbsp;  or sql&nbsp;&nbsp;  denied.&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  alert(&quot;Error: status code is &quot; + xmlHttp.status);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  <br>
}<br>
&nbsp;&nbsp;&nbsp;  &lt;/script&gt;</p>
<p>&lt;/head&gt;<br>
&lt;body&gt;<br>
&nbsp;&nbsp;&nbsp;  &lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;div&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;h1 align=&quot;center&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  验证用户名是否存在&lt;/h1&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;table align=&quot;center&quot; style=&quot;width: 487px&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;tr&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td style=&quot;width: 70px&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  用户名：&lt;/td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td style=&quot;width: 231px&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;input id=&quot;username&quot; onchange=&quot;CheckUserName();&quot; type=&quot;text&quot; /&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;input id=&quot;Button1&quot; type=&quot;button&quot; value=&quot;button&quot; onclick=&quot;CheckUserName();&quot; /&gt;&lt;/td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td id=&quot;Msg1&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;asp:Label ID=&quot;Msg&quot; runat=&quot;server&quot; ForeColor=&quot;Blue&quot;&gt;&lt;/asp:Label&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/tr&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;tr&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td style=&quot;width: 70px&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td style=&quot;width: 231px&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/td&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/tr&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/table&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/div&gt;<br>
&nbsp;&nbsp;&nbsp;  &lt;/form&gt;<br>
&lt;/body&gt;<br>
&lt;/html&gt;</p>
<p>LoginValidate.ashx</p>
<p>&lt;%@ WebHandler Language=&quot;C#&quot; Class=&quot;LoginValidate&quot; %&gt;</p>
<p>using System;<br>
using System.Web;<br>
using System.Data;<br>
using System.Data.SqlClient;<br>
using System.Configuration;</p>
<p>public class LoginValidate : IHttpHandler {<br>
&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  public void ProcessRequest (HttpContext context) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //context.Response.ContentType = &quot;text/plain&quot;;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //context.Response.Write(&quot;Hello World&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  context.Response.ContentType = &quot;text/plain&quot;;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  string username = context.Request.QueryString[&quot;username&quot;].ToString();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  string strSQL = &quot;select username from users where username='&quot; + username + &quot;'&quot;;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (ReDataSet(strSQL).Tables[0].Rows.Count &gt; 0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  context.Response.Write(&quot;该用户已经有人使用！&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (username.Trim().Length&gt;int.Parse(&quot;0&quot;))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  context.Response.Write(&quot;恭喜你！&quot; + username + &quot;可以使用！&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  context.Response.Write(&quot;请您输入用户名！&quot;);&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  System.Threading.Thread.Sleep(1000);</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  //数据库连接字符串<br>
&nbsp;&nbsp;&nbsp;  public static string strCon = &quot;Data Source=.;database=test;uid=sa;pwd=;&quot;;</p>
<p>&nbsp;&nbsp;&nbsp;  /// &lt;summary&gt;<br>
&nbsp;&nbsp;&nbsp;  /// 执行SQL语句，返回DataSet<br>
&nbsp;&nbsp;&nbsp;  /// &lt;/summary&gt;<br>
&nbsp;&nbsp;&nbsp;  /// &lt;param name=&quot;strSQL&quot;&gt;&lt;/param&gt;<br>
&nbsp;&nbsp;&nbsp;  /// &lt;returns&gt;&lt;/returns&gt;<br>
&nbsp;&nbsp;&nbsp;  public DataSet ReDataSet(string strSQL)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // SqlConnection con = new SqlConnection(strCon);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  using (SqlConnection con = new SqlConnection(ConfigurationManager.AppSettings[&quot;ConnectionString&quot;]))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  try<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  con.Open();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  SqlDataAdapter da = new SqlDataAdapter(strSQL, con);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  DataSet ds = new DataSet();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  da.Fill(ds);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return ds;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  catch (Exception ex)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  throw new Exception(ex.Message);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  finally<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  con.Close();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  /// &lt;summary&gt;<br>
&nbsp;&nbsp;&nbsp;  /// 不重复调用<br>
&nbsp;&nbsp;&nbsp;  /// &lt;/summary&gt;<br>
<br>
&nbsp;&nbsp;&nbsp;  public bool IsReusable {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  get {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return false;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  }</p>
<p>}</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/Ajax">Ajax</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/abcd67114fa291c3a7ef3f00.html#comment">查看评论</a>]]></description>
        <pubDate>2008-07-06  16:36</pubDate>
        <category><![CDATA[Ajax]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/abcd67114fa291c3a7ef3f00.html</guid>
</item>

<item>
        <title><![CDATA[ASP.net防SQL注入]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/786a5ab42ecbc9768bd4b259.html]]></link>
        <description><![CDATA[
		
		<p>一，验证方法</p>
<p> /**//// &lt;summary&gt;<br>
  ///SQL注入过滤<br>
  /// &lt;/summary&gt;<br>
  /// &lt;param name=&quot;InText&quot;&gt;要过滤的字符串&lt;/param&gt;<br>
  /// &lt;returns&gt;如果参数存在不安全字符，则返回true&lt;/returns&gt;<br>
  public static bool SqlFilter2(string InText)<br>
  {<br>
&nbsp;&nbsp;  string word=&quot;and|exec|insert|select|delete|update|chr|mid|master|or|truncate|char|declare|join&quot;;<br>
&nbsp;&nbsp;  if(InText==null)<br>
&nbsp;&nbsp;&nbsp;  return false;<br>
&nbsp;&nbsp;  foreach(string i in word.Split('|'))<br>
&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;  if((InText.ToLower().IndexOf(i+&quot; &quot;)&gt;-1)||(InText.ToLower().IndexOf(&quot; &quot;+i)&gt;-1))<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;  return true;<br>
&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;  return false;<br>
  }</p>
<p>二，Global.asax 事件</p>
<p>  /**//// &lt;summary&gt;<br>
  /// 当有数据时交时，触发事件<br>
  /// &lt;/summary&gt;<br>
  /// &lt;param name=&quot;sender&quot;&gt;&lt;/param&gt;<br>
  /// &lt;param name=&quot;e&quot;&gt;&lt;/param&gt;<br>
  protected void Application_BeginRequest(Object sender, EventArgs e)<br>
  {<br>
&nbsp;&nbsp;  //遍历Post参数，隐藏域除外<br>
&nbsp;&nbsp;  foreach(string i in this.Request.Form)<br>
&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;  if(i==&quot;__VIEWSTATE&quot;)continue;<br>
&nbsp;&nbsp;&nbsp;  this.goErr(this.Request.Form[i].ToString());&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;  //遍历Get参数。<br>
&nbsp;&nbsp;  foreach(string i in this.Request.QueryString)<br>
&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;  this.goErr(this.Request.QueryString[i].ToString());&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;  }<br>
  }</p>
<p>三，Global中的一个方法</p>
<p>  /**//// &lt;summary&gt;<br>
  /// 校验参数是否存在SQL字符<br>
  /// &lt;/summary&gt;<br>
  /// &lt;param name=&quot;tm&quot;&gt;&lt;/param&gt;<br>
  private void goErr(string tm)<br>
  {<br>
&nbsp;&nbsp;  if(WLCW.Extend.CValidity.SqlFilter2(tm))<br>
&nbsp;&nbsp;&nbsp;  this.Response.Redirect(&quot;/error.html&quot;);<br>
  }</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/Sqlserver">Sqlserver</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/786a5ab42ecbc9768bd4b259.html#comment">查看评论</a>]]></description>
        <pubDate>2008-07-06  15:35</pubDate>
        <category><![CDATA[Sqlserver]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/786a5ab42ecbc9768bd4b259.html</guid>
</item>

<item>
        <title><![CDATA[阿里旺旺群发器v1.03(免费版)]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/a90110ef7c211aeace1b3e99.html]]></link>
        <description><![CDATA[
		
		<p>此群发器是本人采用C#2.0开发的，希望对各位商家在业务宣传上有些帮助</p>
<p><font color="#ff0000">此软件需要微软的net framework 2.0运行库支持<br>
</font>framework 2.0可以从以下地址下载：<br>
(微软官方)<a href="http://www.microsoft.com/downloads/details.aspx?familyid=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&amp;displaylang=zh-cn" target="_blank">http://www.microsoft.com/downloads/details.aspx?familyid=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&amp;displaylang=zh-cn</a><br>
(天空软件)<a href="http://www.skycn.com/soft/39946.html" target="_blank">http://www.skycn.com/soft/39946.html</a><br>
(华军软件)<a href="http://www.newhua.com/soft/38669.htm" target="_blank">http://www.newhua.com/soft/38669.htm</a><br>
<br>
群发器下载地址：<a href="http://huliduo.com/download/WangWangSend_v1.03.rar" target="_blank"><font color="#7a9f0e">http://huliduo.com/download/WangWangSend_v1.03.rar</font></a></p>
<p>使用帮助：<a href="http://bbs.huliduo.com/showtopic-19.aspx">http://bbs.huliduo.com/showtopic-19.aspx</a></p>
<p> </p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/%C4%AC%C8%CF%B7%D6%C0%E0">默认分类</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/a90110ef7c211aeace1b3e99.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-20  23:42</pubDate>
        <category><![CDATA[默认分类]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/a90110ef7c211aeace1b3e99.html</guid>
</item>

<item>
        <title><![CDATA[捕获asp.net下的未处理异常]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/60630bd422c13a04a18bb790.html]]></link>
        <description><![CDATA[
		
		Apache与Tomcat的区别 
<p>ihttpModule vs ihttpHandler <br>
内部机制：<br>
1.ihttpModule（粘合剂，侦听application事件或用户自定义事件。）<br>
2.ihttpHandler（可以自定义对特定资源进行处理）<br>
2.ihttpHandlerFactory(可以用来进行在自定义ihttpmodule或标准的ihttpModule之间进行选择)</p>
<p>ihttpHandler拦截httpRequest.<br>
ihttpModule是事件侦听器（其作用跟glob.aspx有些相同）</p>
<p>捕获asp.net下的未处理异常 <br>
对软件开发，有个基本的要求，就是要屏蔽掉未处理的异常，在系统出错的时候显示一个友好的界面给用户，同时，保存错误信息到日志中。在asp.net下，未处理的异常会引发HttpApplication.Error 事件，因此，我们可以很简单地实现这个feature。<br>
1、写一个类实现IHttpModule接口，挂接该事件，在事件处理中执行log的功能；<br>
2、在web.config中的customErrors配置节，指定defaultRedirect，并置mode的值为On。</p>
<p> </p>
<p><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;customErrors mode=&quot;RemoteOnly&quot; defaultRedirect=&quot;GenericErrorPage.htm&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;error statusCode=&quot;403&quot; redirect=&quot;NoAccess.htm&quot; /&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;error statusCode=&quot;404&quot; redirect=&quot;FileNotFound.htm&quot; /&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/customErrors&gt;</p>
<p>asp.net中当服务器出错时显示指定的错误页面同时把错误信息写入系统日志文件的探讨</p>
<p><br>
一，在Web.config中填写出错时显示的页面，可以根据不同的statusCode显示不同的出错页面。<br>
&nbsp;&nbsp;&nbsp; &lt;customErrors mode=&quot;On&quot;&nbsp;&nbsp; //如果设置为Off则出错只返回错误信息，不会跳到自己的指定页面defaultRedirect=&quot;/error/customerrorpage.aspx&quot;&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp; &lt;error statusCode=&quot;404&quot; redirect=&quot;/error/404Page.aspx&quot;/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp; &lt;error statusCode=&quot;403&quot; redirect=&quot;/error/403page.aspx&quot;/&gt;<br>
&nbsp;&nbsp; &lt;/customErrors&gt; </p>
<p>二,在Global.asax文件中添加应用出错代码，写入系统日志文件<br>
protected void Application_Error(Object sender, EventArgs e)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exception LastError = Server.GetLastError();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String ErrMessage = LastError.ToString();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String LogName&nbsp;&nbsp; = &quot;MyLog&quot;;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String Message = &quot;Url &quot; + Request.Path + &quot; Error: &quot; + ErrMessage;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create Event Log if It Doesn't Exist<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!EventLog.SourceExists(LogName))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog.CreateEventSource(LogName, LogName);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog Log = new EventLog();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log.Source&nbsp;&nbsp; = LogName;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //These are the five options that will display a different icon.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log.WriteEntry(Message, EventLogEntryType.Information, 1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log.WriteEntry(Message, EventLogEntryType.Error, 2);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log.WriteEntry(Message, EventLogEntryType.Warning, 3);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log.WriteEntry(Message, EventLogEntryType.SuccessAudit, 4);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log.WriteEntry(Message, EventLogEntryType.FailureAudit, 5);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
三，现在你可以进行测试了。<br>
我在Default.aspx.cs中产生一个错误，果然跳到默认的错误页面！<br>
private void Page_Load(object sender, System.EventArgs e)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Put user code to initialize the page here<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int y=0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int x=1/y;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (Exception Err)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new Exception(&quot;404&quot;);//我想产生不同的错误，对应web.config中的statusCode,该如何实现？<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Err.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p><br>
9.获取错误信息并到指定页面</p>
<p>　　不要使用Response.Redirect,而应该使用Server.Transfer </p>
<p>　　e.g </p>
<p>// in global.asax <br>
protected void Application_Error(Object sender, EventArgs e) { <br>
if (Server.GetLastError() is HttpUnhandledException) <br>
Server.Transfer(&quot;MyErrorPage.aspx&quot;); </p>
<p>//其余的非HttpUnhandledException异常交给ASP.NET自己处理就okay了 :) <br>
} <br>
　　Redirect会导致post－back的产生从而丢失了错误信息，所以页面导向应该直接在服务器端执行，这样就可以在错误处理页面得到出错信息并进行相应的处理 </p>
<p><br>
11.自定义异常处理</p>
<p>//自定义异常处理类 <br>
using System; <br>
using System.Diagnostics; </p>
<p>namespace MyAppException <br>
{ <br>
　/// ＜summary＞ <br>
　/// 从系统异常类ApplicationException继承的应用程序异常处理类。 <br>
　/// 自动将异常内容记录到Windows NT/2000的应用程序日志 <br>
　/// ＜/summary＞ <br>
　public class AppException:System.ApplicationException <br>
　{ <br>
　　public AppException() <br>
　　{ <br>
　　　if (ApplicationConfiguration.EventLogEnabled)LogEvent(&quot;出现一个未知错误。&quot;); <br>
　　} </p>
<p>　public AppException(string message) <br>
　{ <br>
　　LogEvent(message); <br>
　} </p>
<p>　public AppException(string message,Exception innerException) <br>
　{ <br>
　　LogEvent(message); <br>
　　if (innerException != null) <br>
　　{ <br>
　　　LogEvent(innerException.Message); <br>
　　} <br>
　} </p>
<p>　//日志记录类 <br>
　using System; <br>
　using System.Configuration; <br>
　using System.Diagnostics; <br>
　using System.IO; <br>
　using System.Text; <br>
　using System.Threading; </p>
<p>　namespace MyEventLog <br>
　{ <br>
　　/// ＜summary＞ <br>
　　/// 事件日志记录类，提供事件日志记录支持 <br>
　　/// ＜remarks＞ <br>
　　/// 定义了4个日志记录方法 (error, warning, info, trace) <br>
　　/// ＜/remarks＞ <br>
　　/// ＜/summary＞ <br>
　　public class ApplicationLog <br>
　　{ <br>
　　　/// ＜summary＞ <br>
　　　/// 将错误信息记录到Win2000/NT事件日志中 <br>
　　　/// ＜param name=&quot;message&quot;＞需要记录的文本信息＜/param＞ <br>
　　　/// ＜/summary＞ <br>
　　　public static void WriteError(String message) <br>
　　　{ <br>
　　　　WriteLog(TraceLevel.Error, message); <br>
　　　} </p>
<p>　　　/// ＜summary＞ <br>
　　　/// 将警告信息记录到Win2000/NT事件日志中 <br>
　　　/// ＜param name=&quot;message&quot;＞需要记录的文本信息＜/param＞ <br>
　　　/// ＜/summary＞ <br>
　　　public static void WriteWarning(String message) <br>
　　　{ <br>
　　　　WriteLog(TraceLevel.Warning, message);　　 <br>
　　　} </p>
<p>　　　/// ＜summary＞ <br>
　　　/// 将提示信息记录到Win2000/NT事件日志中 <br>
　　　/// ＜param name=&quot;message&quot;＞需要记录的文本信息＜/param＞ <br>
　　　/// ＜/summary＞ <br>
　　　public static void WriteInfo(String message) <br>
　　　{ <br>
　　　　WriteLog(TraceLevel.Info, message); <br>
　　　} <br>
　　　/// ＜summary＞ <br>
　　　/// 将跟踪信息记录到Win2000/NT事件日志中 <br>
　　　/// ＜param name=&quot;message&quot;＞需要记录的文本信息＜/param＞ <br>
　　　/// ＜/summary＞ <br>
　　　public static void WriteTrace(String message) <br>
　　　{ <br>
　　　　WriteLog(TraceLevel.Verbose, message); <br>
　　　} </p>
<p>　　　/// ＜summary＞ <br>
　　　/// 格式化记录到事件日志的文本信息格式 <br>
　　　/// ＜param name=&quot;ex&quot;＞需要格式化的异常对象＜/param＞ <br>
　　　/// ＜param name=&quot;catchInfo&quot;＞异常信息标题字符串.＜/param＞ <br>
　　　/// ＜retvalue＞ <br>
　　　/// ＜para＞格式后的异常信息字符串，包括异常内容和跟踪堆栈.＜/para＞ <br>
　　　/// ＜/retvalue＞ <br>
　　　/// ＜/summary＞ <br>
　　　public static String FormatException(Exception ex, String catchInfo) <br>
　　　{ <br>
　　　　StringBuilder strBuilder = new StringBuilder(); <br>
　　　　if (catchInfo != String.Empty) <br>
　　　　{ <br>
　　　　　strBuilder.Append(catchInfo).Append(&quot;\r\n&quot;); <br>
　　　　} <br>
　　　　strBuilder.Append(ex.Message).Append(&quot;\r\n&quot;).Append(ex.StackTrace); <br>
　　　　return strBuilder.ToString(); <br>
　　　} </p>
<p>　　　/// ＜summary＞ <br>
　　　/// 实际事件日志写入方法 <br>
　　　/// ＜param name=&quot;level&quot;＞要记录信息的级别（error,warning,info,trace).＜/param＞ <br>
　　　/// ＜param name=&quot;messageText&quot;＞要记录的文本.＜/param＞ <br>
　　　/// ＜/summary＞ <br>
　　　private static void WriteLog(TraceLevel level, String messageText) <br>
　　　{ <br>
　　　　try <br>
　　　　{ <br>
　　　　　EventLogEntryType LogEntryType; <br>
　　　　　switch (level) <br>
　　　　　{ <br>
　　　　　　case TraceLevel.Error: <br>
　　　　　　　LogEntryType = EventLogEntryType.Error; <br>
　　　　　　　break; <br>
　　　　　　case TraceLevel.Warning: <br>
　　　　　　　LogEntryType = EventLogEntryType.Warning; <br>
　　　　　　　break; <br>
　　　　　　case TraceLevel.Info: <br>
　　　　　　　LogEntryType = EventLogEntryType.Information; <br>
　　　　　　　break; <br>
　　　　　　case TraceLevel.Verbose: <br>
　　　　　　　LogEntryType = EventLogEntryType.SuccessAudit; <br>
　　　　　　　break; <br>
　　　　　　default: <br>
　　　　　　　LogEntryType = EventLogEntryType.SuccessAudit; <br>
　　　　　　　break; <br>
　　　　　} </p>
<p>　　　　　EventLog eventLog = new EventLog(&quot;Application&quot;, ApplicationConfiguration.EventLogMachineName, ApplicationConfiguration.EventLogSourceName ); <br>
　　　　　//写入事件日志 <br>
　　　　　eventLog.WriteEntry(messageText, LogEntryType); </p>
<p>　　　　} <br>
　　　catch {} //忽略任何异常 <br>
　　} <br>
　} //class ApplicationLog <br>
} </p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/asp%2Enet">asp.net</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/60630bd422c13a04a18bb790.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-20  23:26</pubDate>
        <category><![CDATA[asp.net]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/60630bd422c13a04a18bb790.html</guid>
</item>

<item>
        <title><![CDATA[如何在子线程中操作窗体上的控件]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/eefc88fae796919259ee90a6.html]]></link>
        <description><![CDATA[
		
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><font size="3"><span style=" mso-ascii- mso-hansi-">一般来说，直接在子线程中对窗体上的控件操作是会出现异常，这是由于子线程和运行窗体的线程是不同的空间，因此想要在子线程来操作窗体上的控件，是不可能简单的通过控件对象名来操作，但不是说不能进行操作，微软提供了</span><span><font face="Times New Roman">Invoke</font></span><span style=" mso-ascii- mso-hansi-">的方法，其作用就是让子线程告诉窗体线程来完成相应的控件操作。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span><font face="Times New Roman" size="3"> </font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style=" mso-ascii- mso-hansi-"><font size="3">现在用一个用线程控制的进程条来说明，大致的步骤如下：</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt; mso-list: l0 level1 lfo1; "><span style="mso-fareast-"><span style="mso-list: Ignore"><font face="Times New Roman"><font size="3">1．</font><span style="font: 7pt  Times New Roman ">  </span></font></span></span><font size="3"><span style=" mso-ascii- mso-hansi-">创建</span><span><font face="Times New Roman">Invoke</font></span><span style=" mso-ascii- mso-hansi-">函数，大致如下：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray">&lt;summary&gt;</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: gray">///</span><span style="color: green"> Delegate function to be invoked by main thread</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray">&lt;/summary&gt;</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: blue">private</span> <span style="color: blue">void</span> InvokeFun()</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>{</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: blue">if</span>( prgBar.Value &lt; 100 )</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>prgBar.Value = prgBar.Value + 1;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>}</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span><font face="Times New Roman" size="3"> </font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt; mso-list: l0 level1 lfo1; "><span style="mso-fareast-"><span style="mso-list: Ignore"><font face="Times New Roman"><font size="3">2．</font><span style="font: 7pt  Times New Roman ">  </span></font></span></span><span style=" mso-ascii- mso-hansi-"><font size="3">子线程入口函数：</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray">&lt;summary&gt;</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: gray">///</span><span style="color: green"> Thread function interface</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray">&lt;/summary&gt;</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: blue">private</span> <span style="color: blue">void</span> ThreadFun()</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>{</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: green">//Create invoke method by specific function</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>MethodInvoker mi = <span style="color: blue">new</span> MethodInvoker( <span style="color: blue">this</span>.InvokeFun );</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: blue">for</span>( <span style="color: blue">int</span> i = 0; i &lt; 100; i++ )</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>{</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span><span style="color: blue">this</span>.BeginInvoke( mi );</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>Thread.Sleep( 100 );</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>}</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>}</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span><font face="Times New Roman" size="3"> </font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt; mso-list: l0 level1 lfo1; "><span style="mso-fareast-"><span style="mso-list: Ignore"><font face="Times New Roman"><font size="3">3．</font><span style="font: 7pt  Times New Roman ">  </span></font></span></span><span style=" mso-ascii- mso-hansi-"><font size="3">创建子线程：</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>Thread thdProcess = <span style="color: blue">new</span> Thread( <span style="color: blue">new</span> ThreadStart( ThreadFun ) );</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </span>thdProcess.Start();</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span><font face="Times New Roman" size="3"> </font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span><span style="mso-tab-count: 1"><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style=" mso-ascii- mso-hansi-">备注：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span><span style="mso-tab-count: 2"><font face="Times New Roman" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="font-size: 10pt; color: blue;  mso-hansi- mso-font-kerning: 0pt">using</span><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"> System.Threading;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span><span style="mso-tab-count: 2"><font face="Times New Roman" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="font-size: 10pt; color: blue;  mso-hansi- mso-font-kerning: 0pt">private</span><span style="font-size: 10pt;  mso-hansi- mso-font-kerning: 0pt"> System.Windows.Forms.ProgressBar prgBar;</span></p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/c%23">c#</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/eefc88fae796919259ee90a6.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-18  18:18</pubDate>
        <category><![CDATA[c#]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/eefc88fae796919259ee90a6.html</guid>
</item>

<item>
        <title><![CDATA[最新搜索引擎收录地址大全]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/ead2fd1eb50da6f11bd57648.html]]></link>
        <description><![CDATA[
		
		以下是中文搜索网站收录地址<br>
百度搜索网站登录口：<a href="http://www.baidu.com/search/url_submit.html" target="_blank">http://www.baidu.com/search/url_submit.html</a><br>
Google网站登录口：<a href="http://www.google.com/intl/zh-CN/add_url.html" target="_blank">http://www.google.com/intl/zh-CN/add_url.html</a><br>
孙悟空网站登录口：<a href="http://www.sunwukong.cn/add.php" target="_blank">http://www.sunwukong.cn/add.php</a><br>
天网搜索网站登录口：<a href="http://home.tianwang.com/denglu.htm" target="_blank">http://home.tianwang.com/denglu.htm</a><br>
奇摩网站登录口：<a href="http://tw.dir.yahoo.com/step/generally.html" target="_blank">http://tw.dir.yahoo.com/step/generally.html</a><br>
窝窝网web2.0登录口：<a href="http://www.mywowo.com/web2.asp" target="_blank">http://www.mywowo.com/web2.asp</a><br>
麦布搜索网站登录：<a href="http://www.mybu.net/submit.asp" target="_blank">http://www.mybu.net/submit.asp</a><br>
Live Search网站登录口：<a href="http://beta.search.msn.com/docs/submit.aspx" target="_blank">http://beta.search.msn.com/docs/submit.aspx</a><br>
千度搜索网站登录口：<a href="http://www.qiandu.com/protocol.asp" target="_blank">http://www.qiandu.com/protocol.asp</a><br>
中国目录网站登录口：<a href="http://www.china-dir.org/addsite.htm" target="_blank">http://www.china-dir.org/addsite.htm</a><br>
巴辣香港搜寻器登录口：<a href="http://www.balaa.com/cgi-bin/search/add.cgi" target="_blank">http://www.balaa.com/cgi-bin/search/add.cgi</a><br>
北极星搜索登录口：<a href="http://www.beijixing.com.cn/cgi-bin/add.cgi" target="_blank">http://www.beijixing.com.cn/cgi-bin/add.cgi</a><br>
百晓搜索网站登录口：<a href="http://www.baixiao.cn/all/free_add.asp" target="_blank">http://www.baixiao.cn/all/free_add.asp</a><br>
凯希搜索网站登录口：<a href="http://www2d.biglobe.ne.jp/~kinryou/cgi/url.html" target="_blank">http://www2d.biglobe.ne.jp/~kinryou/cgi/url.html</a><br>
爱问搜索网站登录口：<a href="http://iask.com/guest/add_url.php" target="_blank">http://iask.com/guest/add_url.php</a><br>
赛迪免费登录口：<a href="http://itsearch.ccidnet.com/appl/appl_xz.htm" target="_blank">http://itsearch.ccidnet.com/appl/appl_xz.htm</a> <br>
网易免费登录口：<a href="http://odp.163.com/site/auditSiteList.m" target="_blank">http://odp.163.com/site/auditSiteList.m</a> <br>
雅虎免费登录口：<a href="http://cn.yahoo.com/docs/info/suggest.html" target="_blank">http://cn.yahoo.com/docs/info/suggest.html</a> <br>
中华网登录口：<a href="http://202.84.11.68:66/web/frontward/free/free_search.asp" target="_blank">http://202.84.11.68:66/web/frontward/free/free_search.asp</a> <br>
搜豹免费登录口：<a href="http://search.sobao.com/Computers_and_Internet/Personal" target="_blank">http://search.sobao.com/Computers_and_Internet/Personal</a><br>
alltheweb登录口：<a href="http://www.alltheweb.com/add_url.php" target="_blank">http://www.alltheweb.com/add_url.php</a> <br>
国信登录口：<a href="http://search.gxchina.com/login/Login.htm" target="_blank">http://search.gxchina.com/login/Login.htm</a> <br>
晨曦免费登录口：<a href="http://www.mingbu.com/cxsearch/add.asp" target="_blank">http://www.mingbu.com/cxsearch/add.asp</a> <br>
协通免费登录口：<a href="http://www.net2asp.com.cn/search/regform.htm" target="_blank">http://www.net2asp.com.cn/search/regform.htm</a> <br>
朝鲜迷免费登录口：<a href="http://www.168world.com/cgi-bin/link2000/link.cgi?id=dprk" target="_blank">http://www.168world.com/cgi-bin/link2000/link.cgi?id=dprk</a>&amp;a_method=write <br>
法律网免费登录口：<a href="http://www.law-lib.com/lawseek/wzdl.asp" target="_blank">http://www.law-lib.com/lawseek/wzdl.asp</a> <br>
银河免费登录口：<a href="http://search.inhe.net/navigate.asp" target="_blank">http://search.inhe.net/navigate.asp</a> <br>
酷亿免费登录口：<a href="http://www.ku68.com/home/webreg.asp" target="_blank">http://www.ku68.com/home/webreg.asp</a> <br>
星星免费登录口：<a href="http://www.xxsl.net/regsta1.asp?sortid=153" target="_blank">http://www.xxsl.net/regsta1.asp?sortid=153</a> <br>
y4免费登录口：<a href="http://drckness.jahee.com/free/kulink.asp" target="_blank">http://drckness.jahee.com/free/kulink.asp</a> <br>
天下免费登录口：<a href="http://www.8eee.com/wzdl_sy.asp" target="_blank">http://www.8eee.com/wzdl_sy.asp</a> <br>
维华免费登录口：<a href="http://211.99.40.148/html/gsjj_wzdl.htm" target="_blank">http://211.99.40.148/html/gsjj_wzdl.htm</a> <br>
搜鼠免费登录口：<a href="http://sosoo.cnool.net/intro.asp" target="_blank">http://sosoo.cnool.net/intro.asp</a> <br>
尤里卡免费登录口：<a href="http://www.ulika.com/linkaddr/welcome.asp" target="_blank">http://www.ulika.com/linkaddr/welcome.asp</a> <br>
阳光免费登录口：<a href="http://www.jc.gov.cn/userlink/useraddlink.htm" target="_blank">http://www.jc.gov.cn/userlink/useraddlink.htm</a> <br>
1608搜网登录口：<a href="http://search.1608.com/addu.cgi" target="_blank">http://search.1608.com/addu.cgi</a> <br>
中国168登录口：<a href="http://www.china168.com/chaoshi/it/regsta1.asp?sortid=242" target="_blank">http://www.china168.com/chaoshi/it/regsta1.asp?sortid=242</a> <br>
绿界免费登录口：<a href="http://ep.sunup.net/add.php" target="_blank">http://ep.sunup.net/add.php</a> <br>
商情168搜索登陆录口：<a href="http://search.168yx.com/add.php" target="_blank">http://search.168yx.com/add.php</a> <br>
中国搜索同盟登录口：<a href="http://service.chinasearch.com.cn/web/frontward/free/free_protocol.htm" target="_blank">http://service.chinasearch.com.cn/web/frontward/free/free_protocol.htm</a> <br>
TOM搜索登录口：<a href="http://search.tom.com/tools/weblog/log.php" target="_blank">http://search.tom.com/tools/weblog/log.php</a><br>
<br>
-----------------------------------<br>
以下是英文搜索网站收录地址 <br>
<br>
HotBot登录口：<a href="http://www.hotbot.com/prefs_filters.asp?prov=Inktomifilter=web" target="_blank">http://www.hotbot.com/prefs_filters.asp?prov=Inktomifilter=web</a> <br>
netscape登录口：<a href="http://about.netscape.com/" target="_blank">http://about.netscape.com/</a> <br>
intelseek登录口：<a href="http://intelseek.com/add_url_form.asp" target="_blank">http://intelseek.com/add_url_form.asp</a> <br>
NetSearch登录口：<a href="http://www.netsearch.org/promo/submit.htm" target="_blank">http://www.netsearch.org/promo/submit.htm</a> <br>
AddMe登录口：<a href="http://www.addme.com/s0new.htm" target="_blank">http://www.addme.com/s0new.htm</a> <br>
Link it All登录口：<a href="http://www.that-special-gift.com/ffa/links.html" target="_blank">http://www.that-special-gift.com/ffa/links.html</a> <br>
Voyager登录口：<a href="http://www.voyagersearch.com/cgi-bin/q/search.cgi?NAVG=AddURL" target="_blank">http://www.voyagersearch.com/cgi-bin/q/search.cgi?NAVG=AddURL</a> <br>
Gigablast登录口：<a href="http://www.gigablast.com/addurl" target="_blank">http://www.gigablast.com/addurl</a> <br>
Aeiwei登录口：<a href="http://www.aeiwi.com/submit.html" target="_blank">http://www.aeiwi.com/submit.html</a> <br>
Infotiger登录口：<a href="http://www.infotiger.com/addurl.html" target="_blank">http://www.infotiger.com/addurl.html</a> <br>
Nationaldirectory登录口：<a href="http://www.nationaldirectory.com/addurl/" target="_blank">http://www.nationaldirectory.com/addurl/</a> <br>
WhatUseek登录口：<a href="http://www.whatuseek.com/addurl-secondary.shtml" target="_blank">http://www.whatuseek.com/addurl-secondary.shtml</a> <br>
Exactseek登录口：<a href="http://www.exactseek.com/add.html" target="_blank">http://www.exactseek.com/add.html</a> <br>
Walhello登录口：<a href="http://www.walhello.com/addlinkgl.html" target="_blank">http://www.walhello.com/addlinkgl.html</a> <br>
Scrubtheweb登录口：<a href="http://www.scrubtheweb.com/addurl.html" target="_blank">http://www.scrubtheweb.com/addurl.html</a><br>
dmoz的登陆地址: <a href="http://dmoz.org/World/Chinese_Simplified" target="_blank">http://dmoz.org/World/Chinese_Simplified</a> <br> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/%C4%AC%C8%CF%B7%D6%C0%E0">默认分类</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/ead2fd1eb50da6f11bd57648.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-12  21:16</pubDate>
        <category><![CDATA[默认分类]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/ead2fd1eb50da6f11bd57648.html</guid>
</item>

<item>
        <title><![CDATA[用C#2.0实现网络蜘蛛(WebSpider)]]></title>
        <link><![CDATA[http://hi.baidu.com/yueqiangsh/blog/item/0db90226566cbd128a82a1c3.html]]></link>
        <description><![CDATA[
		
		<p>摘要：本文讨论了如何使用C#2.0实现抓取网络资源的网络蜘蛛。使用这个程序，可以通过一个入口网址(如http://www.comprg.com.cn)来扫描整个互联网的网址，并将这些扫描到的网址所指向的网络资源下载到本地。然后可以利用其他的分析工具对这些网络资源做进一步地分析，如提取关键词、分类索引等。也可以将这些网络资源作为数据源来实现象Google一样的搜索引擎。<br>
关键词：C#2.0，Html，网络蜘蛛, 键树，正则表达式</p>
<p>一、引言<br>
<br>
&nbsp;&nbsp;&nbsp;  在最近几年，以Google为首的搜索引擎越来越引起人们的关注。由于在Google出现之前，很多提供搜索服务的公司都是使用人工从网络上搜集信息，并将这些信息分类汇总后作为搜索引擎的数据源。如yahoo公司一开始就是通过数千人不停地从网上搜集供查询的信息。这样做虽然信息的分类会很人性化，也比较准确，但是随着互联网信息爆炸式地增长，通过人工的方式来搜集信息已经不可能满足网民对信息的需求了。然而，这一切随着Google的出现而得到了彻底改变。Google一反常规的做法，通过程序7*24地从网上不停地获取网络资源，然后通过一些智能算法分析这些被下载到本地的网络资源，最后将这些分析后的数据进行索引后就形成了一套完整的基本上不需要人工干预的搜索引擎。使用这种模式的搜索引擎甚至可以在几天之内就可获取Internet中的所有信息，同时也节省了大量的资金和时间成本。而这种搜索引擎最重要的组成部分之一就是为搜索引擎提供数据源的网络蜘蛛。也就是说，实现网络蜘蛛是实现搜索引擎的第一步，也是最重要的一步。<br>
<br>
二、网络蜘蛛的基本实现思想和实现步骤<br>
<br>
&nbsp;&nbsp;&nbsp;  网络蜘蛛的主要作用是从Internet上不停地下载网络资源。它的基本实现思想就是通过一个或多个入口网址来获取更多的URL，然后通过对这些URL所指向的网络资源下载并分析后，再获得这些网络资源中包含的URL，以此类推，直到再没有可下的URL为止。下面是用程序实现网络蜘蛛的具体步骤。<br>
<br>
&nbsp;&nbsp;&nbsp;  1. 指定一个（或多个）入口网址(如<a href="http://www.comprg.com.cn),并将这个网址加入到下载队列中(这时下载队列中只有一个或多个入口网址">http://www.comprg.com.cn），并将这个网址加入到下载队列中（这时下载队列中只有一个或多个入口网址</a>）。<br>
&nbsp;&nbsp;&nbsp;  2. 负责下载网络资源的线程从下载队列中取得一个或多个URL，并将这些URL所指向的网络资源下载到本地（在下载之前，一般应该判断一下这个URL是否已经被下载过，如果被下载过，则忽略这个URL）。如果下载队列中没有URL，并且所有的下载线程都处于休眠状态，说明已经下载完了由入口网址所引出的所有网络资源。这时网络蜘蛛会提示下载完成，并停止下载。<br>
&nbsp;&nbsp;&nbsp;  3. 分析这些下载到本地的未分析过的网络资源（一般为html代码），并获得其中的URL（如标签&lt;a&gt;中href属性的值）。<br>
&nbsp;&nbsp;&nbsp;  4. 将第3步获得的URL加入到下载队列中。并重新执行第2步。<br>
<br>
三、实现数据的输入输出<br>
<br>
&nbsp;&nbsp;&nbsp;  从实现网络蜘蛛的步骤中我们可以看出，下载队列的读、写URL的操作一直贯穿于整个系统中。虽然这个下载队列可以用.Queue类实现，但是各位读者要清楚地知道，在互联网上的URL可不是几十个、几百个这么少。而是以千万计的。这么多的URL显然不能保存在内存中的Queue对象中。因此，我们需要将它保存在容量更大的存储空间中，这就是硬盘。<br>
&nbsp;&nbsp;&nbsp;  本文采用了一个普通的文本文件来保存需要下载和分析的URL（这个文本文件也就是下载队列）。存储格式是每一行为一个URL。既然将URL都保存在了文本文件中，就需要对这个文本文件进行读写。因此，在本节实现了一个用于操作这个文本文件的FileIO类。<br>
&nbsp;&nbsp;&nbsp;  在实现FileIO类之前，先来说一下要如何操作这个文本文件。既然要将这个文件作为队列使用，那么就需要对这个文件进行追加行和从文件开始部分读取数据操作。让我们首先来实现向文件中追加行操作。实现代码如下：<br>
<br>
&nbsp;&nbsp;&nbsp;  向文件中追加行的实现代码<br>
// 这两个变量为类全局变量<br>
private FileStream fsw; <br>
private StreamWriter sw;<br>
<br>
// 创建用于向文件中追加行的文件流和StreamWriter对象<br>
public void OpenWriteFile(string file)<br>
{<br>
if (!File.Exists(file)) // 如果文件不存在，先创建这个文件<br>
File.Create(file).Close();<br>
// 以追加模式打开这个文件<br>
fsw = new FileStream(file, FileMode.Append ,FileAccess.Write, FileShare.ReadWrite);<br>
// 根据创建的FileStream对象来创建StreamWriter对象<br>
sw = new StreamWriter(fsw);<br>
}<br>
// 关闭写文件流<br>
public void CloseWriteFile()<br>
{<br>
if (fsr != null)<br>
fsw.Close();<br>
}<br>
// 向文件中追加一行字符串<br>
public void WriteLine(string s)<br>
{<br>
sw.WriteLine(s);<br>
sw.Flush(); // 刷新写入缓冲区，使这一行对于读文件流可见<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  在实现上述的代码时要注意，在创建FileStream对象时，必须使用FileShare.ReadWrite，否则这个文件无法被两个或两个以上的Stream打开，也就是说下面要介绍的读文件流将无法操作这个被写文件流打开的文件。从文件中读取行的实现代码如下：<br>
<br>
&nbsp;&nbsp;&nbsp;  从文件中读取行的实现代码<br>
// 这两个变量为类全局变量<br>
private FileStream fsr;<br>
private StreamReader sr; <br>
<br>
// 创建用于读取文件行的文件流和StreamWriter对象<br>
public void OpenReadFile(string file)<br>
{<br>
if (!File.Exists(file)) // 如果文件不存在，首先创建这个文件<br>
File.Create(file).Close();<br>
fsr = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Read, <br>
FileShare.ReadWrite); <br>
sr = new StreamReader(fsr);<br>
}<br>
// 关闭读文件流<br>
public void CloseReadFile()<br>
{<br>
if(fsr != null)<br>
fsr.Close();<br>
}<br>
// 从文件中读取一行<br>
public string ReadLine()<br>
{<br>
if(sr.EndOfStream) // 如果文件流指针已经指向文件尾部，返回null<br>
return null;<br>
return sr.ReadLine();<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  除了上述的读写文件的代码外，FileIO还提供了一个IsEof方法用来判断文件流指针是否位于文件尾部。IsEof方法的实现代码如下如下：<br>
<br>
IsEof方法的实现代码<br>
// 用于判断文件流指针是否位于文件尾部<br>
public bool IsEof()<br>
{<br>
return sr.EndOfStream;<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  FileIO类不仅仅用于对下载队列的读写。在后面我们还会讲到，网络蜘蛛通过多线程下载网络资源时，每一个线程将自己下载的网络资源保存在属于自己的一个目录中。每个这样的目录都有一个index.txt文件，这个文件保存了当前目录的网络资源的URL。向index.txt文件中追加URL也用到了FileIO（index.txt不需要读取，只需要不断地追加行）。<br>
<br>
<br>
四、线程类的实现<br>
<br>
&nbsp;&nbsp;&nbsp;  要想使网络蜘蛛在有限的硬件环境下尽可能地提高下载速度。最廉价和快捷的方法就是使用多线程。在.net framework2.0中提供了丰富的线程功能。其中的核心线程类是Thread。一般可使用如下的代码创建并运行一个线程：<br>
<br>
&nbsp;&nbsp;&nbsp;  在C#中使用线程的演示代码<br>
private void fun()<br>
{<br>
// 线程要执行的代码<br>
}<br>
public void testThread()<br>
{ <br>
Thread thread;<br>
thread = new Thread(fun); // 创建一个Thread对象，并将fun设为线程运行的方法<br>
thread.Start(); // 运行一个线程<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  虽然上面的代码比较简单地创建并运行了一个线程，但是这段代码看起来仍然不够透明，也就是客户端在调用线程时仍然需要显式地使用Thread类。下面我们来实现一个用于创建线程的MyThread类。C#中的任何类只需要继承这个类，就可以自动变成一个线程类。MyThread类的代码如下：<br>
<br>
&nbsp;&nbsp;&nbsp;  MyThread类的实现代码<br>
// 任何C#类继承MyThread后，就会自动变成一个线程类<br>
class MyThread <br>
{<br>
private Thread thread;<br>
public MyThread()<br>
{<br>
thread = new Thread(run); // 创建Thread对象<br>
}<br>
// 用于运行线程代码的方法，MyThread的子类必须覆盖这个方法<br>
public virtual void run() <br>
{ <br>
}<br>
public void start()<br>
{<br>
thread.Start(); // 开始运行线程，也就是开始执行run方法<br>
}<br>
// 使当前线程休眠millisecondsTimeout毫秒<br>
public void sleep(int millisecondsTimeout)<br>
{<br>
Thread.Sleep(millisecondsTimeout); <br>
}<br>
}<br>
<br>
<br>
&nbsp;&nbsp;&nbsp;  我们可参照如下的代码使用MyThread类：<br>
<br>
&nbsp;&nbsp;&nbsp;  测试的ThreadClass类的代码<br>
class ThreadClass : MyThread<br>
{<br>
public override void run()<br>
{<br>
// 要执行的线程代码<br>
} <br>
}<br>
<br>
// 测试ThreadClass类<br>
public void testThreadClass()<br>
{<br>
ThreadClass tc = new ThreadClass();<br>
tc.start(); // 开始运行线程，也就是执行run方法<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  各位读者可以看看，上面的代码是不是要比直接使用Thread类更方便、直观、易用，还有些面向对象的感觉！<br>
<br>
五、用多线程下载网络资源<br>
<br>
&nbsp;&nbsp;&nbsp;  一般来说，网络蜘蛛都是使用多线程来下载网络资源的。至于如何使用多线程来下载，各个版本的网络蜘蛛不尽相同。为了方便和容易理解，本文所讨论的网络蜘蛛采用了每一个线程负责将网络资源下载到一个属于自己的目录中，也就是说，每一个线程对应一个目录。而在当前目录中下载的网络资源达到一定的数目后（如5000），这个线程就会再建立一个新目录，并从0开始计数继续下载网络资源。在本节中将介绍一个用于下载网络资源的线程类DownLoadThread。这个类的主要功能就是从下载队列中获得一定数量的URL，并进行下载和分析。在DownLoadThread类中涉及到很多其他重要的类，这些类将在后面的部分介绍。在这里我们先看一下DownLoadThread类的实现代码。<br>
<br>
&nbsp;&nbsp;&nbsp;  DownLoadThread类的代码<br>
class DownLoadThread : MyThread<br>
{<br>
// ParseResource类用于下载和分析网络资源<br>
private ParseResource pr = new ParseResource(); <br>
private int currentCount = 0; // 当前下载目录中的网页数<br>
// 用于向每个线程目录中的index.txt中写当前目录的URL<br>
private FileIO fileIO = new FileIO(); <br>
private string path; // 当前的下载目录（后面带&ldquo;\&quot;）<br>
private string[] patterns; // 线程不下载符合patterns中的正则表达式的URL<br>
public bool stop = false; // stop为true，线程退出<br>
public int threadID; // 当前线程的threadID，用于区分其他的线程<br>
<br>
public DownLoadThread(string[] patterns)<br>
{<br>
pr.findUrl += findUrl; // 为findUrl事件赋一个方法<br>
this.patterns = patterns;<br>
} <br>
// 这是一个事件方法，每获得一个URL时发生<br>
private void findUrl(string url)<br>
{<br>
Common.addUrl(url); // 将获得的URL加到下载队列中<br>
}<br>
private void openFile() // 打开下载目录中的index.txt文件<br>
{<br>
fileIO.CloseWriteFile();<br>
fileIO.OpenWriteFile(path + Common.indexFile); <br>
}<br>
public override void run() // 线程运行方法<br>
{<br>
LinkedList&lt;string&gt; urls = new LinkedList&lt;string&gt;();<br>
path = Common.getDir(); // 获得下载目录<br>
openFile(); <br>
while (!stop) <br>
{<br>
// 当下载队列中没有URL时，进行循环等待<br>
while (!stop &amp;&amp; urls.Count == 0) <br>
{ <br>
Common.getUrls(urls, 20); // 从下载队列中获得20个url<br>
if (urls.Count == 0) // 如果未获得url<br>
{<br>
// 通知系统当前线程已处于等待状态，<br>
// 如果所有的线程都处于等待状态，<br>
// 说明所有的网络资源都被下载完了<br>
Common.threadWait(threadID); <br>
sleep(5000); // 当前线程休眠5秒<br>
}<br>
}<br>
StringBuilder sb = new StringBuilder();<br>
foreach (string url in urls) // 循环对这20个url进行循环下载分析<br>
{<br>
if (stop) break;<br>
// 如果当前下载目录的资源文件数大于等于最大文件数目时，<br>
// 建立一个新目录，并继续下载<br>
if (currentCount &gt;= Common.maxCount)<br>
{<br>
path = Common.getDir();<br>
openFile();<br>
currentCount = 0; // 目录<br>
}<br>
// 每个下载资源文件名使用5位的顺序号保存（没有扩展名），<br>
// 如00001、00002。下面的语句是格式化文件名<br>
string s = string.Format(&quot;{0:D5}&quot;, currentCount + 1);<br>
sb.Remove(0, sb.Length);<br>
sb.Append(s);<br>
sb.Append(&quot;:&quot;);<br>
sb.Append(url);<br>
try<br>
{<br>
// 下载和分析当前的url<br>
pr.parse(url, path + s, patterns); <br>
Common.Count++; <br>
// 将当前的url写入index.txt<br>
fileIO.WriteLine(sb.ToString());<br>
currentCount++;<br>
}<br>
catch (Exception e)<br>
{<br>
<br>
} <br>
} <br>
urls.Clear();<br>
} <br>
}<br>
}<br>
}<br>
<br>
六、分析网络资源<br>
<br>
&nbsp;&nbsp;&nbsp;  对下载的网络资源进行分析是网络蜘蛛中最重要的功能之一。这里网络资源主要指的是html代码中&lt;a&gt;标签的href属性值。状态和状态之间会根据从html文件中读入的字符进行切换。下面是状态之间切换的描述。<br>
<br>
状态0：读入'&lt;'字符后切换到状态1，读入其他的字符，状态不变。<br>
状态1：读入'a'或'A'，切换到状态2，读入其他的字符，切换到状态0。<br>
状态2：读入空格或制表符(\t)，切换到状态3，读入其他的字符，切换到状态0。<br>
状态3：读入'&gt;'，成功获得一个&lt;a&gt;，读入其他的字符，状态不变。为了更容易说明问题。在本文给出的网络蜘蛛中只提取了html代码中&lt;a&gt;中的href属性中的url。本文中所采用的分析方法是分步进行提取href。首先将html代码中的&lt;a&gt;标签整个提出来。不包括&lt;/a&gt;和前面的字符，如&lt;a href=&quot;http://www.comprg.com.cn&quot;&gt;comprg&lt;/a&gt;中只提取&lt;a href=&quot;http://www.comprg.com.cn&quot;&gt;，而comprg&lt;/a&gt;将被忽略，因为这里并没有url。<br>
本文使用了一个状态机来的提取&lt;a&gt;，这个状态机分为五个状态（0 至 4）。第一个状态是初始态，最后一个状态为终止态，如果到达最后一个状态，说明已经成功获得了一个&lt;a&gt;<br>
<br>
&nbsp;&nbsp;&nbsp;  状态机如图1所示。<br>
<br>
<img height="164" src="http://www.comprg.com.cn/net/n03/02/image001.jpg" width="518" border="0"><br>
<br>
图1<br>
<br>
&nbsp;&nbsp;&nbsp;  最后一个双环的状态是最终态。下面让我们来看看获得&lt;a&gt;的实现代码。<br>
<br>
getA方法的实现<br>
// 获得html中的&lt;a&gt;<br>
private void getA()<br>
{<br>
char[] buffer = new char[1024];<br>
int state = 0;<br>
String a = &quot;&quot;;<br>
<br>
while (!sr.EndOfStream)<br>
{<br>
int n = sr.Read(buffer, 0, buffer.Length);<br>
for (int i = 0; i &lt; n; i++)<br>
{<br>
switch (state)<br>
{<br>
case 0: // 状态0<br>
if (buffer[i] == '&lt;') // 读入的是'&lt;'<br>
{<br>
a += buffer[i];<br>
state = 1; // 切换到状态1<br>
}<br>
break;<br>
case 1: // 状态1<br>
if (buffer[i] == 'a' || buffer[i] == 'A') // 读入是'a'或'A'<br>
{<br>
a += buffer[i];<br>
state = 2; // 切换到状态2<br>
}<br>
else<br>
{<br>
a = &quot;&quot;;<br>
state = 0; // 切换到状态0<br>
}<br>
break;<br>
case 2: // 状态2<br>
if (buffer[i] == ' ' || buffer[i] == '\t') // 读入的是空格或'\t'<br>
{<br>
a += buffer[i];<br>
state = 3;<br>
}<br>
else<br>
{<br>
a = &quot;&quot;;<br>
state = 0; // 切换到状态0<br>
}<br>
break;<br>
case 3: // 状态3<br>
if (buffer[i] == '&gt;') // 读入的是'&gt;'，已经成功获得一个&lt;a&gt;<br>
{<br>
a += buffer[i];<br>
try<br>
{<br>
string url = getUrl(getHref(a)); // 获得&lt;a&gt;中的href属性的值<br>
if (url != null)<br>
{<br>
if (findUrl != null)<br>
findUrl(url); // 引发发现url的事件<br>
<br>
}<br>
}<br>
catch (Exception e)<br>
{<br>
}<br>
state = 0; // 在获得一个&lt;a&gt;后，重新切换到状态0<br>
}<br>
else<br>
a += buffer[i];<br>
break;<br>
}<br>
}<br>
}<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  在getA方法中除了切换到状态0外，其他的状态切换都将已经读入的字符赋给String变量a，如果最后发现变量a中的字符串不可能是&lt;a&gt;后，就将a清空，并切换到状态0后重新读入字符。<br>
在getA方法中使用了一个重要的方法getHref来从&lt;a&gt;中获得href部分。getHref方法的实现如下：<br>
<br>
&nbsp;&nbsp;&nbsp;  getHref方法的实现<br>
// 从&lt;a&gt;中获得Href<br>
private String getHref(string a)<br>
{<br>
try<br>
{<br>
string p = @&quot;href\s*=\s*('[^']*'|&quot;&quot;[^&quot;&quot;]*&quot;&quot;|\S+\s+)&quot;; // 获得Href的正则表达式<br>
MatchCollection matches = Regex.Matches(a, p,<br>
RegexOptions.IgnoreCase |<br>
RegexOptions.ExplicitCapture);<br>
<br>
foreach (Match nextMatch in matches)<br>
{<br>
return nextMatch.Value; // 返回href<br>
}<br>
return null;<br>
}<br>
catch (Exception e)<br>
{<br>
throw e;<br>
}<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  在getHref方法中使用了正则表达式从&lt;a&gt;中获得href。在&lt;a&gt;中正确的href属性格式有三种情况，这三种情况的主要区别是url两边的符号，如单引号、双引号或没有符号。这三种情况如下所示：<br>
情况1： &lt;a href = &quot;http://www.comprg.com.cn&quot; &gt; comprg&lt;/a&gt;<br>
情况2： &lt;a href = 'http://www.comprg.com.cn' &gt; comprg&lt;/a&gt;<br>
情况3： &lt;a href = http://www.comprg.com.cn &gt; comprg&lt;/a&gt;<br>
&nbsp;&nbsp;&nbsp;  getHref方法中的p存储了用于过滤这三种情况的href，也就是说，使用正则表达式可以获得上述三种情况的href如下：<br>
<br>
从情况1获得得的href：href = &quot;http://www.comprg.com.cn&quot;<br>
从情况2获得得的href：href = 'http://www.comprg.com.cn'<br>
从情况3获得得的href：href = <a href="http://www.comprg.com.cn/">http://www.comprg.com.cn</a><br>
<br>
&nbsp;&nbsp;&nbsp;  在获得上述的href后，需要将url提出来。这个功能由getUrl完成，这个方法的实现代码如下：<br>
<br>
getUrl方法的实现<br>
// 从href中提取url<br>
private String getUrl(string href)<br>
{<br>
try<br>
{<br>
if (href == null) return href; <br>
int n = href.IndexOf('='); // 查找'='位置<br>
String s = href.Substring(n + 1);<br>
int begin = 0, end = 0;<br>
string sign = &quot;&quot;;<br>
if (s.Contains(&quot;\&quot;&quot;)) // 第一种情况<br>
sign = &quot;\&quot;&quot;;<br>
else if (s.Contains(&quot;'&quot;)) // 第二种情况<br>
sign = &quot;'&quot;; <br>
else // 第三种情况<br>
return getFullUrl(s.Trim());<br>
begin = s.IndexOf(sign);<br>
end = s.LastIndexOf(sign);<br>
<br>
return getFullUrl(s.Substring(begin + 1, end - begin - 1).Trim());<br>
}<br>
catch (Exception e)<br>
{<br>
throw e;<br>
}<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  在获得url时有一点应该注意。有的url使用的是相对路径，也就是没有&ldquo;http://host&rdquo;部分，但将url保存时需要保存它们的完整路径。这就需要根据相对路径获得它们的完整路径。这个功能由getFullUrl方法完成。这个方法的实现代码如下：<br>
<br>
getFullUrl方法的实现代码<br>
// 将相对路径变为绝对路径<br>
private String getFullUrl(string url) <br>
{<br>
try<br>
{<br>
if (url == null) return url;<br>
if (processPattern(url)) return null; // 过滤不想下载的url<br>
// 如果url前有http://或https://，为绝对路径，按原样返回<br>
if (url.ToLower().StartsWith(&quot;http://&quot;) || url.ToLower().StartsWith(&quot;https://&quot;))<br>
return url;<br>
Uri parentUri = new Uri(parentUrl);<br>
string port = &quot;&quot;;<br>
if (!parentUri.IsDefaultPort)<br>
port = &quot;:&quot; + parentUri.Port.ToString();<br>
if (url.StartsWith(&quot;/&quot;)) // url以&quot;/&quot;开头，直接放在host后面<br>
return parentUri.Scheme + &quot;://&quot; + parentUri.Host + port + url;<br>
else // url不以&quot;/&quot;开头，放在url的路径后面<br>
{<br>
string s = &quot;&quot;;<br>
s = parentUri.LocalPath.Substring(0, parentUri.LocalPath.LastIndexOf(&quot;/&quot;));<br>
return parentUri.Scheme + &quot;://&quot; + parentUri.Host + port + s + &quot;/&quot; + url;<br>
}<br>
}<br>
catch (Exception e)<br>
{<br>
throw e;<br>
}<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  在ParseResource中还提供了一个功能就是通过正则表达式过滤不想下载的url，这个功能将通过processPattern方法完成。实现代码如下：<br>
<br>
&nbsp;&nbsp;&nbsp;  processPattern方法的实现代码<br>
// 如果返回true，表示url符合pattern，否则，不符合模式<br>
private bool processPattern(string url)<br>
{<br>
foreach (string p in patterns)<br>
{<br>
<br>
if (Regex.IsMatch(url, p, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture) <br>
&amp;&amp; !p.Equals(&quot;&quot;))<br>
return true;<br>
}<br>
return false;<br>
}<br>
&nbsp;&nbsp;&nbsp;  ParseResource类在分析html代码之前，先将html下载到本地的线程目录中，再通过FileStream打开并读取待分析的数据。ParseResource类其他的实现代码请读者参阅本文提供的源代码。<br>
<br>
七、键树的实现<br>
<br>
&nbsp;&nbsp;&nbsp;  在获取Url的过程中，难免重复获得一些Url。这些重复的Url将大大增加网络蜘蛛的下载时间，以及会导致其他的分析工具重复分析同一个html。因此，就需要对过滤出重复的Url，也就是说，要使网络蜘蛛下载的Url都是唯一的。达到这个目的的最简单的方法就是将已经下载过的Url保存到一个集合中，然后在下载新的Url之前，在这个集合中查找这个新的Url是否被下载过，如果下载过，就忽略这个Url。<br>
&nbsp;&nbsp;&nbsp;  这个功能从表面上看非常简单，但由于我们处理的是成千上万的Url，要是将这些Url简单地保存在类似List一样的集合中，不仅会占用大量的内存空间，而且当Url非常多时，如一百万。这时每下载一个Url，就要从这一百万的Url中查找这个待下载的Url是否存在。虽然可以使用某些查找算法（如折半查找）来处理，但当数据量非常大时，任何查找算法的效率都会大打折扣。因此，必须要设计一种新的存储结构来完成这个工作。这个新的数据存储结构需要具有两个特性:<br>
<br>
&nbsp;&nbsp;&nbsp;  1. 尽可能地减少存储Url所使用的内存。<br>
&nbsp;&nbsp;&nbsp;  2. 查找Url的速度尽可能地快（最好的可能是查找速度和Url的数量无关）。<br>
<br>
&nbsp;&nbsp;&nbsp;  下面先来完成第一个特性。一般一个Url都比较长，如平均每个Url有50个字符。如果有很多Url，每个Url占50个字符，一百万个Url就是会占用50M的存储空间。而我们保存Url的目的只有一个，就是查找某一个Url是否存在。因此，只需要将Url的Hashcode保存起来即可。由于Hashcode为Int类型，因此，Hashcode要比一个Url字符串使用更少的存储空间。<br>
&nbsp;&nbsp;&nbsp;  对于第二个特性，我们可以使用数据结构中的键树来解决。假设有一个数是4532。首先将其转换为字符串。然后每个键树节点有10个（0至9）。这样4532的存储结构如图2所示：<br>
<br>
<img height="354" src="http://www.comprg.com.cn/net/n03/02/image003.jpg" width="277" border="0"><br>
<br>
图2<br>
<br>
&nbsp;&nbsp;&nbsp;  从上面的数据结构可以看出，查找一个整数只和这个整数的位数有关，和整数的数量无关。这个键树的实现代码如下：<br>
<br>
&nbsp;&nbsp;&nbsp;  KeyTree的实现代码<br>
class KeyTreeNode // 键树节点的结构<br>
{<br>
// 指向包含整数下一个的结点的指针<br>
public KeyTreeNode[] pointers = new KeyTreeNode[10];<br>
// 结束位标志，如果为true，表示当前结点为整数的最后一位<br>
public bool[] endFlag = new bool[10]; <br>
}<br>
class KeyTree<br>
{<br>
private KeyTreeNode rootNode = new KeyTreeNode(); // 根结点<br>
// 向键树中添加一个无符号整数<br>
public void add(uint n)<br>
{ <br>
string s = n.ToString();<br>
KeyTreeNode tempNode = rootNode;<br>
int index = 0;<br>
for (int i = 0; i &lt; s.Length; i++)<br>
{<br>
index = int.Parse(s[i].ToString()); // 获得整数每一位的值<br>
if (i == s.Length - 1) // 在整数的最后一位时，将结束位设为true<br>
{<br>
tempNode.endFlag[index] = true;<br>
break;<br>
}<br>
if (tempNode.pointers[index] == null) // 当下一个结点的指针为空时，新建立一个结点对象<br>
tempNode.pointers[index] = new KeyTreeNode();<br>
tempNode = tempNode.pointers[index];<br>
}<br>
}<br>
// 判断一个整数是否存在<br>
public bool exists(uint n)<br>
{<br>
string s = n.ToString();<br>
KeyTreeNode tempNode = rootNode;<br>
int index = 0;<br>
for (int i = 0; i &lt; s.Length; i++)<br>
{<br>
if (tempNode != null)<br>
{<br>
index = int.Parse(s[i].ToString());<br>
// 当整数的最后一位的结束标志为true时，表示n存在<br>
if((i == s.Length - 1)&amp;&amp; (tempNode.endFlag[index] == true))<br>
return true;<br>
else<br>
tempNode = tempNode.pointers[index];<br>
}<br>
else<br>
return false;<br>
}<br>
return false;<br>
}<br>
}<br>
<br>
&nbsp;&nbsp;&nbsp;  上面代码中的KeyTreeNode之所以要使用结束标志，而不根据指针是否为空判断某个整数的存在，是因为可能存在长度不相等的整数，如4321和432。如果只使用指针判断。保存4321后，432也会被认为存在。而如果用结束标志后，在值为2的节点的结束标志为false，因此，表明432并不存在。下面的UrlFilter使用了上面的键树来处理Url。<br>
<br>
&nbsp;&nbsp;&nbsp;  UrlFilter类的实现代码<br>
// 用于将url重新组合后再加到键树中<br>
// 如http://www.comprg.com.cn和http://www.comprg.com.cn/是一样的<br>
// 因此，它们的hashcode也要求一样<br>
class UrlFilter <br>
{<br>
public static KeyTree urlHashCode = new KeyTree();<br>
private static object syncUrlHashCode = new object();<br>
private static string processUrl(string url) // 重新组合Url<br>
{<br>
try<br>
{<br>
Uri uri = new Uri(url);<br>
string s = uri.PathAndQuery;<br>
if(s.Equals(&quot;/&quot;))<br>
s = &quot;&quot;;<br>
return uri.Host + s;<br>
}<br>
catch(Exception e)<br>
{<br>
throw e;<br>
}<br>
}<br>
private static bool exists(string url) // 判断url是否存在<br>
{<br>
try<br>
{<br>
lock (syncUrlHashCode)<br>
{<br>
url = processUrl(url);<br>
return urlHashCode.exists((uint)url.GetHashCode());<br>
}<br>
}<br>
catch (Exception e)<br>
{<br>
throw e;<br>
}<br>
}<br>
<br>
public static bool isOK(string url)<br>
{<br>
return !exists(url);<br>
}<br>
// 加处理完的Url加到键树中<br>
public static void addUrl(string url)<br>
{<br>
try<br>
{<br>
lock (syncUrlHashCode)<br>
{<br>
url = processUrl(url);<br>
urlHashCode.add((uint)url.GetHashCode());<br>
}<br>
}<br>
catch (Exception e)<br>
{<br>
throw e;<br>
}<br>
}<br>
<br>
}<br>
<br>
八、其他部分的实现<br>
<br>
&nbsp;&nbsp;&nbsp;  到现在为止，网络蜘蛛所有核心代码都已经完成了。下面让我们做一个界面来使下载过程可视化。界面如图3所示。<br>
<br>
<img height="233" src="http://www.comprg.com.cn/net/n03/02/image005.jpg" width="548" border="0"><br>
<br>
图3<br>
<br>
&nbsp;&nbsp;&nbsp;  这个界面主要通过一个定时器每2秒钟获得个一次网络蜘蛛的下载状态。包括获得的URL数和已经下载的网络资源数。其中这些状态信息都保存在一个Common类的静态变量中。Common类和主界面的代码请读者参阅本文提供的源代码。<br>
<br>
九、结束语<br>
<br>
&nbsp;&nbsp;&nbsp;  至此，网络蜘蛛程序已经全部完成了。但在实际应用中，光靠一台机器下载整个的网络资源是远远不够的。这就需要通过多台机器联合下载。然而这就会给我们带来一个难题。就是这些机器需要对已经下载的Url进行同步。读者可以根据本文提供的例子，将其改成分布式的可多机同时下载的网络蜘蛛。这样网络蜘蛛的下载速度将会有一个质的飞跃。</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/yueqiangsh/blog/category/c%23">c#</a>&nbsp;<a href="http://hi.baidu.com/yueqiangsh/blog/item/0db90226566cbd128a82a1c3.html#comment">查看评论</a>]]></description>
        <pubDate>2008-06-10  23:31</pubDate>
        <category><![CDATA[c#]]></category>
        <author><![CDATA[yueqiangsh]]></author>
		<guid>http://hi.baidu.com/yueqiangsh/blog/item/0db90226566cbd128a82a1c3.html</guid>
</item>


</channel>
</rss>