<?xml version="1.0" encoding="gb2312"?>

<!-- RSS generated by oioj.net on 4/16/2004 ; 感谢LeXRus提供 RSS 2.0 文档; 此文件可自由使用，但请保留此行信息 --> 
<!-- Source download URL: http://blogger.org.cn/blog/rss2.asp       -->
<rss version="2.0">

<channel>
<title>二进制-虚心使人进步，骄傲使人落后。</title>
<link>http://blogger.org.cn/blog/blog.asp?name=binaryluo</link>
<description>binaryluo的博客</description>
<copyright>blogger.org.cn</copyright>
<generator>W3CHINA Blog</generator>
<webMaster>webmaster@blogger.org.cn</webMaster>
<item>
<title><![CDATA[Debian下关联amule和firefox]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=27229</link>
<author>binaryluo</author>
<pubDate>2007/8/13 14:45:00</pubDate>
<description><![CDATA[<P>1.安装amule和amule-utils(两者都必须安装)。</P>
<P>2.在firefox地址栏中输入：about:config，并建立新键值：<BR>New-&gt;Boolean，名字：insert network.protocol-handler.external.ed2k<EM>，值：</EM>true<EM>。</EM></P>
<P>New-&gt;String, 名字：insert network.protocol-handler.app.ed2k，值：/usr/bin/ed2k</P>]]></description>
</item><item>
<title><![CDATA[Debian ls 目录颜色在深色背景下过暗的解决方法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=27052</link>
<author>binaryluo</author>
<pubDate>2007/8/6 11:46:37</pubDate>
<description><![CDATA[
<P>1. 修改~/.bashrc中： </P>
<DIV class=HtmlCode title=点击运行该代码！ style="CURSOR: pointer" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();" ;># enable color support of ls and also add handy aliases<BR>if [ "$TERM" != "dumb" ]; then<BR>&nbsp;&nbsp;&nbsp; #eval "`dircolors -b`"<BR>&nbsp;&nbsp;&nbsp; eval "`dircolors ~/.dircolors`"<BR>&nbsp;&nbsp;&nbsp; alias ls='ls --color=auto'<BR>&nbsp;&nbsp;&nbsp; #alias dir='ls --color=auto --format=vertical'<BR>&nbsp;&nbsp;&nbsp; #alias vdir='ls --color=auto --format=long'<BR>fi</DIV>
<P>2. $dircolors -p &gt; ~/.dircolors</P>
<P>3. 修改~/.dircolors中的：" DIR 01;34 # directory " 为自己喜欢的颜色（共有8种颜色可选，具体请看.dircolors注释），我的改为： </P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
<P>DIR 01;37 # directory</P></DIV>]]></description>
</item><item>
<title><![CDATA[Debian VI 高亮显示及注释颜色过暗更改方法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=27051</link>
<author>binaryluo</author>
<pubDate>2007/8/6 11:32:03</pubDate>
<description><![CDATA[
<OL>
<LI>把/usr/share/vim/vimrc中的"syntax on"取消注释。</LI>
<LI>$mkdir ~/.vim/colors/</LI>
<LI>$cp /usr/share/vim/vim71/colors/desert.vim ~/.vim/colors/</LI>
<LI>修改desert.vim 中的： hi Folded ctermfg=darkgrey ctermbg=NONE 为： hi Folded ctermfg=darkgrey ctermfg=4 ctermbg=7</LI>
<LI>$vi .vimrc 输入一下内容：</LI></OL>
<DIV class=HtmlCode title=点击运行该代码！ style="CURSOR: pointer" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();" ;>" for colorscheme. added by albcamus<BR>if has("gui_running")<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "colorscheme default&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " It doesn't matter whether you comment this or not<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :<BR>else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; colorscheme desert&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " I'd like to use modified desert scheme instead<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " of the default one, in the CLI mode of course;-)<BR>endif</DIV>
<P>&nbsp; 保存并退出。 </P>]]></description>
</item><item>
<title><![CDATA[出栈顺序解法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=17452</link>
<author>binaryluo</author>
<pubDate>2006/8/11 15:56:02</pubDate>
<description><![CDATA[<A><FONT size=2>　</FONT></A><A><FONT size=2>　</FONT></A><FONT size=2> </FONT>
<P><FONT size=2>原题：</FONT></P><SPAN style="FONT-SIZE: 12px">
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><SPAN style="FONT-SIZE: 12px"><FONT size=2>有四个元素a, b, c, d依次进栈，任何时候都可以出栈，请写出所有可能的出栈序列。</FONT></SPAN></DIV></SPAN>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>该题有两种思路：1.直接找出所有正确的解；2.在全集中排除不正确的解，剩余的即为正确解。我将要给出的是第二种思路——间接法求解的过程。<BR><BR>间接法的优点：可以对随机输入的一组序列进行判断，看是否是正确的出栈序列。<BR>间接法的缺点：如果要求解全部正确的出栈序列，需先求出全排列，然后用该判断函数对全排列中的每一组序列进行检验，将正确的序列输出。<BR><BR>简介：<BR>由于题目已经隐性规定“a在b先入栈，b在c先入栈，c在d先入栈，……”如果原始序列用s表示，那么题目隐含条件可归纳为“s[ i ]在s[ i + 1]先入栈”。因此，在出栈的时候，若若j &lt; m &lt; n &lt; k，且s[ j ]和s[ k ]均已出栈，则s[ m ]必不可能在s[ n ]之前出栈。<BR>例：<BR>s = a, b, c, d<BR>若出栈序列的前两个元素是：c, d，则说明a, b还在栈中（a要退栈的前提是b先退栈），此时可以确定正确的出栈序列是：c, d, b, a。</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;检测函数：</FONT></SPAN></SPAN></P><SPAN style="FONT-SIZE: 12px">
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>int sost(char **a, char *s, int p, int n,<BR>&nbsp;&nbsp; void (*view)(char **a, int m, int n))<BR>{<BR>&nbsp;int count;<BR>&nbsp;int flag;<BR>&nbsp;int i, j, k;<BR>&nbsp;Stack *st;<BR>&nbsp;<BR>&nbsp;/* disp(a, p, n); */<BR>&nbsp;count = 0;<BR>&nbsp;st = (Stack *)malloc(sizeof (Stack));<BR>&nbsp;stack_init(st);&nbsp;&nbsp;&nbsp;&nbsp;/* initiate the stack */<BR>&nbsp;for (i = 0; i &lt; p; i ++)&nbsp;/* M is the number of records in list a */<BR>&nbsp;{<BR>&nbsp;&nbsp;flag = 1;<BR>&nbsp;&nbsp;j = 0;<BR>&nbsp;&nbsp;k = 0; <BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;/* deal with a records */<BR>&nbsp;&nbsp;while (j &lt; n &amp;&amp; k &lt; n)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;/* if the element of record match to source's */<BR>&nbsp;&nbsp;&nbsp;if (a[i][j] != s[k])<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;/* revert the sequence out stack */<BR>&nbsp;&nbsp;&nbsp;&nbsp;if (!stack_empty(st) &amp;&amp; a[i][j] == peep(st))<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop(st);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++ j;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push(st, s[k]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++ k;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;++ j;<BR>&nbsp;&nbsp;&nbsp;&nbsp;++ k;<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;}</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;&nbsp;/* test if the sequence is ok */<BR>&nbsp;&nbsp;while (!stack_empty(st) &amp;&amp; j &lt; n)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if (a[i][j] != pop(st))<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;flag = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;break;<BR>&nbsp;&nbsp;&nbsp;}</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;&nbsp;&nbsp;++ j;<BR>&nbsp;&nbsp;}</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;&nbsp;/* print the valid record */<BR>&nbsp;&nbsp;if (flag)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;count ++;<BR>&nbsp;&nbsp;&nbsp;(*view)(a, i, n);<BR>&nbsp;&nbsp;}</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;&nbsp;/* clear the stack */<BR>&nbsp;&nbsp;stack_clear(st);<BR>&nbsp;}</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;stack_destroy(st);<BR>&nbsp;if (st) free(st);<BR>&nbsp;flag = count;</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;return flag;<BR>}</FONT></SPAN></P></DIV>
<P><FONT size=2>附完整原代码：<IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" alt=sost原代码 src="http://blogger.org.cn/blog/uploadfile/2006811161016830.RAR" border=0></FONT></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;编译：用VC++ 6.0打开SOST.dsw。</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 12px"><FONT size=2>&nbsp;运行：</FONT></SPAN><SPAN style="FONT-SIZE: 12px"><SPAN style="FONT-SIZE: 12px"><FONT color=green></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><SPAN style="FONT-SIZE: 12px"><SPAN style="FONT-SIZE: 12px"><BR><BR><FONT size=2>&gt;<FONT color=green>sost</FONT><BR>Usage: sost [-t record] [-a number]<BR><BR>Options:<BR>&nbsp; &nbsp; -t record&nbsp; &nbsp;test the record is valid out-stack sequence or not.<BR>&nbsp; &nbsp; -a number&nbsp; &nbsp;find all valid solutions of the number of full-permutation.<BR><BR>&gt;<FONT color=green>sost -t cba</FONT><BR>cba<BR>Valid seqence.<BR><BR>&gt;<FONT color=green>sost - t cab</FONT><BR>NOT valid sequence.<BR><BR>&gt; <FONT color=green>sost -a 5</FONT><BR>edcba<BR>decba<BR>cedba<BR>dceba<BR>cdeba<BR>bedca<BR>bdeca<BR>cbeda<BR>bceda<BR>dcbea<BR>cdbea<BR>bdcea<BR>cbdea<BR>bcdea<BR>aedcb<BR>adecb<BR>acedb<BR>adceb<BR>acdeb<BR>baedc<BR>abedc<BR>badec<BR>abdec<BR>cbaed<BR>bcaed<BR>acbed<BR>baced<BR>abced<BR>dcbae<BR>cdbae<BR>bdcae<BR>cbdae<BR>bcdae<BR>adcbe<BR>acdbe<BR>badce<BR>abdce<BR>cbade<BR>bcade<BR>acbde<BR>bacde<BR>abcde<BR>count of total solutions is 42.<BR><BR>&gt;</FONT></SPAN></SPAN></DIV></FONT></SPAN></SPAN></SPAN>]]></description>
</item><item>
<title><![CDATA[想研究下cgi]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=16235</link>
<author>binaryluo</author>
<pubDate>2006/7/3 22:41:05</pubDate>
<description><![CDATA[<A><FONT size=2>　</FONT></A><FONT color=#000000 size=2>&nbsp; 在jsp，asp，asp.net，php“横行”的今天，还会有人提起cgi吗？<BR><BR>&nbsp;&nbsp;&nbsp; 记得大一的时候第二次专业实践，老师让用cgi写一个留言板，并且要求用c语言实现。现在回想起来那个时候真的很痛苦——c也不是很熟，对cgi更是前所未闻。虽然最后勉强叫了，但是始终对cgi也是懵里懞懂……<BR><BR>&nbsp;&nbsp;&nbsp; 第二次听说cgi是在大二。一次专业英语课上，教英语的老师（是个外教，主要研究j2ee，兼上我们的专业英语）突然吹起j2ee，说着说着又提到cgi，那时听他说cgi给我留下的印象就是——cgi已经过时了。<BR><BR>&nbsp;&nbsp;&nbsp; 这久突然又想起来cgi，想再研究下这种“古老”的技术。看看到底cgi是否已经过时……<BR><BR>&nbsp;&nbsp;&nbsp; P.S.欢迎对cgi感兴趣或有研究的朋友谈谈自己对cgi的看法。<BR></FONT>]]></description>
</item><item>
<title><![CDATA[[转贴]最近流行的警句!-女生一定要看看]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=16096</link>
<author>binaryluo</author>
<pubDate>2006/6/30 15:16:41</pubDate>
<description><![CDATA[<font size="2"></font><font color="#333399" size="2">骑白马的不一定是王子，他可能是唐僧； <br><br>带翅膀的也不一定是天使，妈妈说，那是鸟人。 <br><br>站的更高，尿的更远。 <br><br>穿别人的鞋，走自己的路，让他们找去吧， <br><br>我不是随便的人。我随便起来不是人 <br><br>女人无所谓正派，正派是因为受到的引诱不够； <br><br>男人无所谓忠诚，忠诚是因为背叛的筹码太低…… <br><br>聪明的女人对付男人，而笨女人对付女人. <br><br>走自己的路，让别人打车去吧. <br><br>水至清则无鱼,人至贱则无敌! <br><br>一大学生最低奋斗目标：农妇，山泉，有点田. <br><br>做爱做的事，交配交的人. <br><br>再过几十年，我们来相会，送到火葬场，全部烧成灰，你一堆，我一堆，谁也不认识谁，全部送到农村做化肥. <br><br>女人谨记：一定要吃好玩好睡好喝好,一但累死了,就有别的女人花咱的钱，住咱的房，睡咱的老公，泡咱的男朋友，还打咱的娃了</font>]]></description>
</item><item>
<title><![CDATA[【原创】用debian的方式编译内核]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=15812</link>
<author>binaryluo</author>
<pubDate>2006/6/24 12:53:11</pubDate>
<description><![CDATA[<A><FONT size=2>　</FONT></A><SPAN style="FONT-SIZE: 12px"><FONT size=2><B>写在前</B><BR>大家如果看了参考文章【1】可能会觉得我接下来要写的跟它里面写的很像啊，怎么还用“原创”？？我之所以在标题前加上“原创”，首先，参考文章【1】里介绍的内容我确实自己实践过；其次，在实施的过程中，有些地方按照它的方法是不行的，或者说是按照它的方法我没有成功，还有些地方它说的不是很清楚的，我又尝试了其他方法，最终搞定，也算是有自己的结论。<BR>本文假设你已经安装了基本系统，主要介绍debian下的内核编译，关于基本系统和桌面的安装网络上有很多资源可以参考，这里将不再赘述。<BR><BR><B>入题</B><BR>1.安装好基本系统后，首先要做的是升级刚安装好的基本系统，这是参考文章【1】中没有提到的，否则在进行后面步骤的时候会遇到老的内核（我的是2.6.8-2）被移除的麻烦。<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code0'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code0 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>apt-get update<BR>apt-get dist-upgrade</FONT></DIV><FONT size=2>2.系统升级完后，先安装等下需要用到的工具软件。按理说升级的时候这些软件大多都已经装好了，如果没装的，输入下面命令安装：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code1'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code1 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>apt-get install kernel-package ncurses-dev fakeroot wget bzip2 module-init-tools initrd-tools procps</FONT></DIV><FONT size=2>3.然后是下载最新的内核源码。最新的内核源码可以在</FONT><A href="http://www.kernel.org/" target=_blank><FONT color=#003366 size=2>http://www.kernel.org/</FONT></A><FONT size=2>上下载。你可以在其他机子或系统上下好后将其拷贝到/usr/src目录；也可以在命令行下用wget下载：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code2'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code2 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>cd /usr/src<BR>wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.16.20.tar.bz2</FONT></DIV><FONT size=2>我安装的时候最新内核是2.6.16.20，现在已经有2.6.17.1了。<BR><BR>4.检查/usr/src目录下是否有linux-2.6.16.20.tar.bz2或你下载的最新版内核存在，解压：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code3'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code3 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>tar jxvf linux-2.6.16.20.tar.bz2</FONT></DIV><FONT size=2>5.制作配置文件，在这里我按照的是参考文章【1】中的方法，直接将现有内核的配置文件考过来用：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code4'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code4 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>cp /boot/config-2.6.8.2 /usr/src/linux-2.6.16.20/.config</FONT></DIV><FONT size=2>6.加载nvidia最新驱动。参考文章【1】中所说的是在testing里有nvidia的源码包，但是我装的时候testing里根本没有，只好又在sources.list里面添加入unstable的源：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code5'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code5 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>deb http://mirror.vmmatrix.net/debian unstable main non-free contrib<BR>deb-src http://mirror.vmmatrix.net/debian unstable main non-free contrib</FONT></DIV><FONT size=2>添加好后，重新更新软件库并安装nvidia源码包：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code6'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code6 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>apt-get update<BR>apt-get install nvidia-kernel-source nvidia-kernel-common</FONT></DIV><FONT size=2>在安装这两个包的时候由于依赖关系，可能会额外的安装其他包，但由于此时使用的是unstable的源，而原来系统用的是testing的源，混合安装可能会出问题，所以我的处理方法是记录下要额外安装的那些包，先到testing里将这些包都安装了，最后又回到unstable下安装上面两个包。我的这种方法有点麻烦，但比较安全，也可能还有其他的方法也能解决这个问题。在下载好nvidia-kernel-source后，在/usr/src下会有一个nvidia-kernel-source.tar.gz包。解压缩：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code7'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code7 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>tar -zxf nvidia-kernel-source.tar.gz</FONT></DIV><FONT size=2>7.现在基本工作已就绪。进入 linux-2.6.16.20目录，先要配置内核：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code8'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code8 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>cd linux-2.6.16.20<BR>make menuconfig</FONT></DIV><FONT size=2>配置内核是比较麻烦的，一个小的错误就可能功亏一篑。所以我也按照参考文章【1】里的方法，只是修改了几个可能出现问题的地方，<FONT color=red>取消</FONT>下面的选项：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em"><FONT size=2>QUOTE:</FONT></DIV>
<DIV class=altbg2 style="BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 10px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>Block Devices -&gt; Low Performance USB Block driver (BLK_DEV_UB)<BR>Graphics Support -&gt; nVidia Riva support (FB_RIVA)<BR>Kernel Hacking -&gt; Use 4Kb for kernel stacks instead of 8Kb (4KSTACKS)<BR>Processor Type and Features -&gt; Local APIC support on uniprocessors&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;(X86_UP_APIC)</FONT></DIV><FONT size=2>另外就是选择了适合自己的处理机类型。<BR><BR>8.配置内核开始编译。命令比较简单：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code9'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code9 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>make-kpkg clean<BR>fakeroot make-kpkg –revision=custom.1.0 kernel_image modules_image</FONT></DIV><FONT size=2>编译过程差不多要1个半小时，结束后，你可以在/usr/src下看到两个deb包：kernel-image-*.deb nvidia-kernel-*.deb。<BR><BR>9.下面就是安装新内核：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code10'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code10 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>dpkg -i kernel-image-*.deb nvidia-kernel-*.deb</FONT></DIV><FONT size=2>10.修改启动项文件。首先制作initrd：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code11'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code11 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>cd /boot<BR>mkinitrd -o /boot/initrd.img-2.6.16.20 2.6.16.20</FONT></DIV><FONT size=2>我使用的是grub管理器，还要修改/boot/grub/menu.lst，正常情况下你会发现menu.lst中已经加入了你的新内核的信息，但是你对照着老内核的信息你会发现有点出入——新内核的位置不对，所以要手动修改：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code12'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code12 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>title&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Debian GNU/Linux, kernel 2.6.16.20<BR>root&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;(hd0,6)<BR>kernel&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /vmlinuz-2.6.16.20 root=/dev/hda8 ro<BR>initrd&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /initrd.img-2.6.16.20<BR>savedefault<BR>boot<BR><BR>title&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Debian GNU/Linux, kernel 2.6.16.20 (recovery mode)<BR>root&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;(hd0,6)<BR>kernel&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /vmlinuz-2.6.16.20 root=/dev/hda8 ro single<BR>initrd&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /initrd.img-2.6.16.20<BR>savedefault<BR>boot</FONT></DIV><FONT size=2>说明:(hd0, 6)的意思是我的第一块硬盘（我只有一块硬盘）的第六个分区（我的linux装在该分区）。<BR>这些都完成以后就可以重启了，你会在grub管理器里发现你的新内核，选择新内核启动就可以了。<BR><BR>11.使用新内核启动后，需要安装nvidia-glx，要保证nvidia-glx的版本跟nvidia-kernel-source的版本是相同的，所以nvidia-kernle-source用的是什么源nvidia-glx也用什么源。因为刚才下载nvidia-kernel-source的时候我的sources.list是unstable的源，后面没有被修改过，所以直接安装：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code13'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code13 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>apt-get install nvidia-glx</FONT></DIV><FONT size=2>之后，修改/etc/X11/xorg.conf，注释掉dri模块：<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code14'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code14 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"i2c"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"bitmap"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"ddc"<BR>#Load&nbsp; &nbsp; &nbsp; &nbsp; "dri"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"extmod"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"freetype"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"glx"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"int10"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"type1"<BR>Load&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"vbe"</FONT></DIV><FONT size=2>12.安装桌面环境（别忘了修改sources.list为testing源）。<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code15'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code15 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>apt-get install x-window-system-core gnome gdm</FONT></DIV><FONT size=2>再重启，gdm加载成功后应该可以看见nvidia的标志，说明nvidia驱动安装也成功了。<BR><BR>13.遗留问题。如果进入系统后如果发现刷新频率调不高，继续修改/etc/X11/xorg.conf:<BR><BR></FONT>
<DIV class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<DIV style="FLOAT: left"><FONT size=2>CODE:</FONT></DIV>
<DIV style="FLOAT: right; TEXT-ALIGN: right"><A class=smalltxt onclick="copycode(findobj('code16'));" href="http://bbs.sei.ynu.edu.cn/viewthread.php?tid=12712&amp;extra=page%3D1#"><FONT color=#003366 size=2>[Copy to clipboard]</FONT></A></DIV></DIV>
<DIV class=altbg2 id=code16 style="CLEAR: both; BORDER-RIGHT: #698cc3 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #698cc3 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: #698cc3 1px solid; WORD-BREAK: break-all; PADDING-TOP: 5px; BORDER-BOTTOM: #698cc3 1px solid"><FONT size=2>HorizSync&nbsp; &nbsp;&nbsp; &nbsp; 30.0 - 81.0<BR>VertRefresh&nbsp; &nbsp;&nbsp;&nbsp;56.0 – 75.0</FONT></DIV><FONT size=2>将水平扫描频率和垂直扫描频率调到你的显示器范围，这两个参数可以在你的显示器说明书上找到。整个编译过程到此也告一段落。<BR><BR><B>结语</B><BR>按照上面步骤做基本不会出什么问题了，可以成功编译内核。如果以后对内核研究的熟悉了，在配置的时候要多花点功夫，这样内核会发挥更好的性能。<BR><BR><B>参考文章</B><BR>【1】Leo Tzao，Debian 安装手记，http://debian.linuxsir.org/main/?q=node/107<BR>【2】Andrew E. Schulman，Debian-nVidia HOWTO，http://home.comcast.net/~andrex/Debian-nVidia/installation.htm</FONT></SPAN><FONT size=2> <BR></FONT>]]></description>
</item><item>
<title><![CDATA[J2EE中的会话管理简介]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=15031</link>
<author>binaryluo</author>
<pubDate>2006/6/4 9:07:38</pubDate>
<description><![CDATA[<A><FONT size=2>　</FONT></A><!--StartFragment --><FONT size=2> 在j2ee中会话管理有四种方法来保存当前的状态：</FONT>
<P></P>
<P><FONT size=2>&nbsp;&nbsp; 1．重写URL<BR>&nbsp;&nbsp; 2．隐藏域<BR>&nbsp;&nbsp; 3．Cookies<BR>&nbsp;&nbsp; 4．Session对象（推荐）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 其中，前两种在HTML里也经常被用到。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 重写URL，就是将要要传递到下一个页面的信息放在该页面URL的后面。<BR>&nbsp;&nbsp; 优点：简单，方便。<BR>&nbsp;&nbsp; 缺点：要传送的信息以明文方式放在URL后面，安全性低；而且一次传递的信息不能超过2000个字符。所以重写URL通常用于传输一些数据量较小，而且信息保密性要求不高的信息。使用格式如下：<BR>&nbsp;&nbsp; </FONT><FONT size=2><STRONG>url?name1=<I>value</I>1&amp;name2=<I>value</I>2&amp;…<BR></STRONG>&nbsp;&nbsp; 例如，在index.jsp页面中有一个提交按钮，而search.jsp是用来处理该按钮要检索的关键字的，用重写URL实现如下：</FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>&lt;input&nbsp;type="submit"&nbsp;name="Submit"&nbsp;<I>value</I>="搜索"&gt;&lt;br/&gt;<BR>&lt;a&nbsp;href="./search.jsp?key=计算机"&gt;高级搜索&lt;/a&gt;<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; 然后在search.jsp中用如下方式取得index.jsp传过来的信息：</FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>String&nbsp;key&nbsp;=&nbsp;request.getParameter(“key”)<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; 在本例中，key的值是“计算机”。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 隐藏域，顾名思义就是可以将要传递的信息隐藏以后传递给下一个页面，其实质就是将表单的method设置为post方式。<BR>&nbsp;&nbsp; 例如，在test.jsp中，写了一个隐藏域，名字叫“id”，值是“1”：</FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>&lt;form&nbsp;method&nbsp;=&nbsp;post&gt;<BR>&lt;input&nbsp;type&nbsp;=&nbsp;hidden&nbsp;name&nbsp;=&nbsp;id&nbsp;<I>value</I>&nbsp;=&nbsp;“1”&gt;<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; 要获得该隐藏域的信息仍然使用request的getParameter方法：</FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>String&nbsp;id&nbsp;=&nbsp;request.getParameter(“id”)<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; 在本例中，id的值是“1”。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; Cookies是将会话信息保存在客户端（浏览器）的方法，只要客户端不清除Cookies，它将永久保存。每个Cookies有一个名字和一个值。<BR>&nbsp;&nbsp; <STRONG>创建一个cookies：</STRONG>&nbsp;&nbsp; </FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>Cookie(String&nbsp;name,&nbsp;String&nbsp;<I>value</I>)<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; <STRONG>发送一个cookies到浏览器：</STRONG>&nbsp;&nbsp; </FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>HttpServletResponse.addCookie(Cookie&nbsp;aCookie)<BR></FONT></DIV>
<P><STRONG><FONT size=2>&nbsp;&nbsp;取cookies的信息：</FONT></STRONG></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>HttpServletRequest.getCookies()</FONT></DIV>
<P><BR><FONT size=2>&nbsp; 示例：<BR></FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
<P><FONT size=2>Public&nbsp;void&nbsp;doPost(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;throws&nbsp;ServletException,&nbsp;IOException&nbsp;{<BR>&nbsp;String&nbsp;userName&nbsp;=&nbsp;request.getParameter(“username”);<BR>&nbsp;String&nbsp;password&nbsp;=&nbsp;request.getParameter(“password”);</FONT></P>
<P><FONT size=2>&nbsp;If&nbsp;(login(userName,&nbsp;password))<BR>&nbsp;{<BR>&nbsp;&nbsp;Cookie&nbsp;c1&nbsp;=&nbsp;new&nbsp;Cookie(“username”,&nbsp;username);<BR>&nbsp;&nbsp;Cookie&nbsp;c2&nbsp;=&nbsp;new&nbsp;Cookie(“password”,&nbsp;password);<BR>&nbsp;&nbsp;Response.addCookie(c1);<BR>&nbsp;&nbsp;Response.addCookie(c2);<BR>&nbsp;&nbsp;Response.setContentType(“test/html”);<BR>}<BR>}</FONT></P></DIV>
<P><FONT size=2>&nbsp;&nbsp; Session对象，应该说是会话管理中最简单，而且是最强大的一种方法。Session对象使用的是HttpSession接口，该接口中有众多可使用的方法，可以去查j2sdk文档，在这里不再赘述。<BR>&nbsp;&nbsp; HttpSession的数据存储方式是：<BR>&nbsp;&nbsp; </FONT><FONT size=2><STRONG>&lt;”key”,&nbsp;object&gt;<BR></STRONG>&nbsp;&nbsp; <STRONG>设置session对象的参数：</STRONG></FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>void&nbsp;setAttribute(String，Object)<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; <STRONG>获取session对象的参数：</STRONG></FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>Object&nbsp;getAttribute(String)<BR></FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; 示例：<BR>&nbsp;&nbsp; Content1Servlet:</FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>Public&nbsp;void&nbsp;doPost(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;throws&nbsp;ServletException,&nbsp;IOException&nbsp;{<BR>&nbsp;HttpSession&nbsp;session&nbsp;=&nbsp;request.getSession(true);<BR>&nbsp;Session.setAttribute(“loggedIn”,&nbsp;new&nbsp;String(“true”));<BR>&nbsp;Response.sendRedirect(“Content2Servlet”);<BR>&nbsp;……<BR>}</FONT></DIV>
<P><FONT size=2>&nbsp;&nbsp; Content2Servlet:</FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>Public&nbsp;void&nbsp;doGet(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;throws&nbsp;ServletException,&nbsp;IOException&nbsp;{<BR>&nbsp;HttpSession&nbsp;session&nbsp;=&nbsp;request.getSession();<BR>&nbsp;if&nbsp;(session&nbsp;==&nbsp;null)<BR>&nbsp;&nbsp;Response.sendRedirect(loginUrl);<BR>&nbsp;else&nbsp;{<BR>&nbsp;&nbsp;String&nbsp;loggedin&nbsp;=&nbsp;(String)session.getAttribute(“loggedIn”);<BR>&nbsp;&nbsp;if&nbsp;(!loggedIn.equals(“true”))<BR>&nbsp;&nbsp;&nbsp;response.sendRedirect(loginUrl);<BR>&nbsp;}<BR>&nbsp;……<BR>}</FONT></DIV><FONT size=2>&nbsp;&nbsp; 通常，保存对象(Object)一般都用Session对象。</FONT>]]></description>
</item><item>
<title><![CDATA[人与兽安全过河问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=15030</link>
<author>binaryluo</author>
<pubDate>2006/6/4 8:50:09</pubDate>
<description><![CDATA[
<P><FONT size=2>&nbsp;&nbsp; <STRONG>题目：</STRONG></FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 有一条河，在河的左岸有3个人和3个野兽要过河。河里有一只船，该船每次最多可以装2个物体（人或兽）。在河两岸上如果人的数目小于兽的数目，人就被兽吃掉。请列出人和兽能安全过河所有方法。</FONT></P>
<P><!--StartFragment --><FONT size=2>&nbsp;&nbsp; <STRONG>算法分析：</STRONG></FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 将某一时刻河岸的整个状态抽象为一个结构体，而没一个状态会由下列5中情况派生出5个子状态：1个人过河，2个人过河，1个兽过河，2个兽过河，1个人和一个兽过河。对每一个子状态进行判断：如果左边和右边都有人，两边的人数必须分别大于等于两边的兽数；如果左边有人，右边没人，左边的人数必须大于左边兽数；如果左边没人，右边有人，右边的人数必须大于右边的兽数。考虑用五元组<!--StartFragment --> （X,Y,U,V,Z）建立模型：X-左边人数，Y-左边兽数，U-右边人数，V-右边兽数，Z-船的位置。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;<STRONG>算法描述：</STRONG></FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
<P><FONT size=2>/* 状态节点 */</FONT></P>
<P><FONT size=2>typedef struct _stNode {<BR>&nbsp;int hl, bl, hr, br;<BR>&nbsp;pos bp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* boat position */<BR>&nbsp;struct _stNode *parent;<BR>} stNode;</FONT></P>
<P><FONT size=2>/* 人兽过河 */</FONT></P>
<P><FONT size=2>bool humbst(stNode st, FILE *fp, void (*opt)(stNode sm, FILE *fp))<BR>{<BR>&nbsp;bool rev = false;</FONT></P>
<P><FONT size=2>&nbsp;do<BR>&nbsp;{<BR>&nbsp;&nbsp;/* 该状态与初始状态相同的情况不操作 */<BR>&nbsp;&nbsp;if (st.hl == N &amp;&amp; st.bl == N &amp;&amp; st.hr == 0 &amp;&amp;<BR>&nbsp;&nbsp;&nbsp;st.br == 0 &amp;&amp; st.bp == left &amp;&amp; st.parent != NULL)<BR>&nbsp;&nbsp;&nbsp;break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;/* 该状态与祖父状态相同的情况不操作 */<BR>&nbsp;&nbsp;if (st.parent != NULL &amp;&amp; st.parent-&gt;parent != NULL)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if ((st.hl == st.parent-&gt;parent-&gt;hl)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp; (st.bl == st.parent-&gt;parent-&gt;bl)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp; (st.hr == st.parent-&gt;parent-&gt;hr)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp; (st.br == st.parent-&gt;parent-&gt;br)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp; (st.bp == st.parent-&gt;parent-&gt;bp))<BR>&nbsp;&nbsp;&nbsp;&nbsp;break;<BR>&nbsp;&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;/* 人数小于兽数的时候不满足 */<BR>&nbsp;&nbsp;if ((st.hl != 0 &amp;&amp; st.hr != 0 &amp;&amp; (st.hl &lt; st.bl || st.hr &lt; st.br))<BR>&nbsp;&nbsp;&nbsp;|| (st.hl != 0 &amp;&amp; st.hr == 0 &amp;&amp; st.hl &lt; st.bl)<BR>&nbsp;&nbsp;&nbsp;|| (st.hl == 0 &amp;&amp; st.hr != 0 &amp;&amp; st.hr &lt; st.br))<BR>&nbsp;&nbsp;&nbsp;break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;/* 中止状态 */<BR>&nbsp;&nbsp;if (st.hl == 0 &amp;&amp; st.bl == 0 &amp;&amp; st.hr == N &amp;&amp;<BR>&nbsp;&nbsp;&nbsp;st.br == N &amp;&amp; st.bp == right)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;opt(st, fp);<BR>&nbsp;&nbsp;&nbsp;rev = true;<BR>&nbsp;&nbsp;&nbsp;break;<BR>&nbsp;&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;/* 正常情况 */<BR>&nbsp;&nbsp;opt(st, fp);<BR>&nbsp;&nbsp;switch (st.bp)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;case left:<BR>&nbsp;&nbsp;&nbsp;rev = humbst_left(st, fp, stDisp);<BR>&nbsp;&nbsp;&nbsp;break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;case right:<BR>&nbsp;&nbsp;&nbsp;rev = humbst_right(st, fp, stDisp);<BR>&nbsp;&nbsp;&nbsp;break;<BR>&nbsp;&nbsp;}<BR>&nbsp;} while (false);</FONT></P>
<P><FONT size=2>&nbsp;return rev;<BR>}</FONT></P>
<P><FONT size=2>bool humbst_left(stNode st, FILE *fp, void (*opt)(stNode sm, FILE *fp))<BR>{<BR>&nbsp;bool rev = false;<BR>&nbsp;stNode st1, st2, st3, st4, st5;</FONT></P>
<P><FONT size=2>&nbsp;if (st.hl &gt;= 1)&nbsp;/* 将左边的一个人运到右边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st1.hl = st.hl - 1;<BR>&nbsp;&nbsp;st1.bl = st.bl;<BR>&nbsp;&nbsp;st1.hr = st.hr + 1;<BR>&nbsp;&nbsp;st1.br = st.br;<BR>&nbsp;&nbsp;st1.bp = right;<BR>&nbsp;&nbsp;st1.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st1, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.hl &gt;= 2)&nbsp;/* 将左边的两个人运到右边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st2.hl = st.hl - 2;<BR>&nbsp;&nbsp;st2.bl = st.bl;<BR>&nbsp;&nbsp;st2.hr = st.hr + 2;<BR>&nbsp;&nbsp;st2.br = st.br;<BR>&nbsp;&nbsp;st2.bp = right;<BR>&nbsp;&nbsp;st2.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st2, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.bl &gt;= 1)&nbsp;/* 将左边的一个兽运到右边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st3.hl = st.hl;<BR>&nbsp;&nbsp;st3.bl = st.bl - 1;<BR>&nbsp;&nbsp;st3.hr = st.hr;<BR>&nbsp;&nbsp;st3.br = st.br + 1;<BR>&nbsp;&nbsp;st3.bp = right;<BR>&nbsp;&nbsp;st3.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st3, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.bl &gt;= 2)&nbsp;/* 将左边的两个兽运到右边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st4.hl = st.hl;<BR>&nbsp;&nbsp;st4.bl = st.bl - 2;<BR>&nbsp;&nbsp;st4.hr = st.hr;<BR>&nbsp;&nbsp;st4.br = st.br + 2;<BR>&nbsp;&nbsp;st4.bp = right;<BR>&nbsp;&nbsp;st4.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st4, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.hl &gt;= 1 &amp;&amp; st.bl &gt;= 1)&nbsp;/* 将左边的一个人一个兽运到右边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st5.hl = st.hl - 1;<BR>&nbsp;&nbsp;st5.bl = st.bl - 1;<BR>&nbsp;&nbsp;st5.hr = st.hr + 1;<BR>&nbsp;&nbsp;st5.br = st.br + 1;<BR>&nbsp;&nbsp;st5.bp = right;<BR>&nbsp;&nbsp;st5.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st5, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;return rev;<BR>}</FONT></P>
<P><FONT size=2>bool humbst_right(stNode st, FILE *fp, void (*opt)(stNode sm, FILE *fp))<BR>{<BR>&nbsp;bool rev = false;<BR>&nbsp;stNode st1, st2, st3, st4, st5;</FONT></P>
<P><FONT size=2>&nbsp;if (st.hr &gt;= 1)&nbsp;/* 将右边的一个人运到左边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st1.hl = st.hl + 1;<BR>&nbsp;&nbsp;st1.bl = st.bl;<BR>&nbsp;&nbsp;st1.hr = st.hr - 1;<BR>&nbsp;&nbsp;st1.br = st.br;<BR>&nbsp;&nbsp;st1.bp = left;<BR>&nbsp;&nbsp;st1.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st1, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.hr &gt;= 2)&nbsp;/* 将右边的两个人运到左边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st2.hl = st.hl + 2;<BR>&nbsp;&nbsp;st2.bl = st.bl;<BR>&nbsp;&nbsp;st2.hr = st.hr - 2;<BR>&nbsp;&nbsp;st2.br = st.br;<BR>&nbsp;&nbsp;st2.bp = left;<BR>&nbsp;&nbsp;st2.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st2, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.br &gt;= 1)&nbsp;/* 将右边的一个兽运到左边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st3.hl = st.hl;<BR>&nbsp;&nbsp;st3.bl = st.bl + 1;<BR>&nbsp;&nbsp;st3.hr = st.hr;<BR>&nbsp;&nbsp;st3.br = st.br - 1;<BR>&nbsp;&nbsp;st3.bp = left;<BR>&nbsp;&nbsp;st3.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st3, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.br &gt;= 2)&nbsp;/* 将右边的两个兽运到左边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st4.hl = st.hl;<BR>&nbsp;&nbsp;st4.bl = st.bl + 2;<BR>&nbsp;&nbsp;st4.hr = st.hr;<BR>&nbsp;&nbsp;st4.br = st.br - 2;<BR>&nbsp;&nbsp;st4.bp = left;<BR>&nbsp;&nbsp;st4.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st4, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;if (st.hr &gt;= 1 &amp;&amp; st.br &gt;= 1)&nbsp;/* 将右边的一个人一个兽运到左边 */<BR>&nbsp;{<BR>&nbsp;&nbsp;st5.hl = st.hl + 1;<BR>&nbsp;&nbsp;st5.bl = st.bl + 1;<BR>&nbsp;&nbsp;st5.hr = st.hr - 1;<BR>&nbsp;&nbsp;st5.br = st.br - 1;<BR>&nbsp;&nbsp;st5.bp = left;<BR>&nbsp;&nbsp;st5.parent = &amp;st;<BR>&nbsp;&nbsp;rev = humbst(st5, fp, opt);<BR>&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;return rev;<BR>}</FONT></P></DIV>
<P><FONT size=2>&nbsp;&nbsp; humbest函数其实就是构造一个状态变迁图（树），然后用opt函数来对该图进行操作（比如说dfs）。 </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;上面算法描述其实就是代码片断了，思路很清晰。我已经编译通过，只需自己添加opt函数和main函数就可以运行了。<!--StartFragment --></FONT></P>]]></description>
</item><item>
<title><![CDATA[TCP数据段的组装]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=13599</link>
<author>binaryluo</author>
<pubDate>2006/4/19 11:07:49</pubDate>
<description><![CDATA[<P><A><FONT size=2>　</FONT></A><FONT size=2>&nbsp;&nbsp;重装TCP数据段，我看了《TCP/IP详解卷二：实现》觉得它里面的实现考虑的很全面，当然也就很复杂。而我组装只是为了监视,所以不必那么复杂，于是自己想了一个方法。现在我已经根据这个方法成功组装TCP分段，所以这个方法是可行的。 另外，我的IP分片的组装用的方法跟这个方法也差不多。<BR><BR>&nbsp;&nbsp;&nbsp; 首先说下存储tcp分段的数据结构：一个二维链表，我把它叫作重装表。具有相同socket对（源ip地址、目的ip地址、源端口号、目的端口号）的tcp数据包放在一个横向的链表里，该链表的头节点只保存了源ip地址、目的ip地址、源端口号、目的端口号这些信息。如下图所示：</FONT></P>
<P><FONT size=2><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006419112711828.GIF" align=middle border=0></FONT></P>
<P><FONT size=2><BR>&nbsp;&nbsp;&nbsp;&nbsp;然后介绍重装TCP数据段的方法：<BR><BR>1.每到来一个tcp数据包(pkt)，我先将该数据包的源ip地址、目的ip地址、源端口号、目的端口号取出来在重装表（tpq_tbl）中纵向的链表中查找有没有与它相匹配的链表(fp)存在，如果有，就把pkt数据包放入与它有相同socket对的fp链中，放入链表的时，我先查找pkt的顺序号在链表中的适当位置，然后才放入；如果没有，则在tpq_tbl中新创建一个该类型的链表头节点，然后再将其放入新创建的链表中。<BR><BR>2.每当在fp中放入一个tcp数据段后，我就检查fp链表中的数据段是否已经到齐了（判断方法下面介绍），若到齐，就将个链表中所有数据段的数据部分拼接到一起，得到应用层报文，然后释放该链表，然后重复1－2步骤；若没到齐，直接重复1－2步骤。<BR><BR>&nbsp;&nbsp;&nbsp; 关于判断一个链表中tcp数据段是否到齐的方法：<BR>&nbsp; &nbsp; 使用的变量说明：<BR>&nbsp; &nbsp; count计数器，表示当前链表中的所有tcp数据段数据部分的长度之和。每当在该链表中加入一个新tcp数据段时，我都会将count累加上该tcp数据段的数据部分的长度。<BR>&nbsp; &nbsp; syn_seq，表示本次tcp连接的第一个数据包的顺序号，也就是建立tcp连接时的第一次握手的SYN包的顺序号。<BR>&nbsp; &nbsp; fin_seq，表示本次tcp连接的最后一个数据包的顺序号，也就是关闭tcp连接时的第二个FIN包的顺序号。<BR><BR>&nbsp; &nbsp; 判断：当(fin_seq - syn_seq)与count相等时，就说明tcp数据段已经到齐，否则就是没有到齐。 <BR></P></FONT>]]></description>
</item><item>
<title><![CDATA[提问前先看下：提问的智慧]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=13561</link>
<author>binaryluo</author>
<pubDate>2006/4/18 9:32:59</pubDate>
<description><![CDATA[<P>&nbsp;&nbsp;&nbsp;这些天在回答网友提问的时候发觉很多问题都可以在winpcap的文档中或是其他资料上找到答案，有些问题又是问得莫名奇妙，所以特地找来《提问的智慧》，希望大家在提问前都看下。</P>
<P>&nbsp;&nbsp; 总之，解决问题之道最终还是靠自己。不要自己都不知道要问什么问题的时候就提问。</P>
<P><!--StartFragment -->&nbsp;原文出处：<A href="http://www.linuxforum.net/doc/smartq-grand.html">http://www.linuxforum.net/doc/smartq-grand.html</A></P>
<CENTER><BR><FONT color=blue>
<H3>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
<CENTER><FONT color=blue>
<H3>How To Ask Questions The Smart Way </H3></FONT><BR>译者 D.H.Grand[本站会员] 
<TABLE cellSpacing=0 cellPadding=0 width="90%" border=0>
<TBODY>
<TR>
<TD><PRE><FONT size=3>                                             
<!-- 在下面粘贴入你的文件 -->

      How To Ask Questions The Smart Way 
      提问的智慧 

      Copyright (C) 2001 by Eric S. Raymond 
      中文版Copyleft 2001 by D.H.Grand(nOBODY/Ginux) 

      英文版：http://www.tuxedo.org/~esr/faqs/smart-questions.html 
      感谢Eric的耐心指点和同意，本文才得以完成并发布，本指南英文版版权为Eric Steven
      Raymond所有，中文版版权由D.H.Grand[nOBODY/Ginux]所有。 

      目录 


      简介 
      提问之前 
      怎样提问 
      谨慎选择论坛 
      尽量使用邮件列表 
      用辞贴切，语法正确，拼写无误 
      用易读格式发送问题 
      使用含义丰富，描述准确的标题 
      精确描述，信息量大 
      话不在多 
      只说症状，不说猜想 
      按时间顺序列出症状 
      别要求私下答复 
      明白你想问什么 
      别问应该自己解决的问题 
      去除无意义的疑问 
      谦逊绝没有害处，而且常帮大忙 
      问题解决后，加个简短说明 
      如何理解答案 
      RTFM和STFW：别烦我啦 
      还是不懂:( 

      面对无礼 
      决不要象个失败者 
      三思而后问 
      好问题，坏问题 
      找不到答案怎么办 

      ==== 
      简介 
      ==== 

      在黑客世界里，当提出一个技术问题时，你能得到怎样的回答？这取决于挖出答案的难
      度，同样取决于你提问的方法。本指南旨在帮助你提高发问技巧，以获取你最想要的答
      案。 

      首先你必须明白，黑客们只偏爱艰巨的任务，或者能激发他们思维的好问题。如若不然，
      我们还来干吗？如果你有值得我们反复咀嚼玩味的好问题，我们自会对你感激不尽。好问
      题是激励，是厚礼，可以提高我们的理解力，而且通常会暴露我们以前从没意识到或者思
      考过的问题。对黑客而言，“问得好！”是发自内心的大力称赞。 

      尽管黑客们有蔑视简单问题和不友善的坏名声，有时看起来似乎我们对新手，对知识贫乏
      者怀有敌意，但其实不是那样的。 

      我们不想掩饰对这样一些人的蔑视--他们不愿思考，或者在发问前不去完成他们应该做的
      事。这种人只会谋杀时间--他们只愿索取，从不付出，无端消耗我们的时间，而我们本可
      以把时间用在更有趣的问题或者更值得回答的人身上。我们称这样的人为“失败者”（由
      于历史原因，我们有时把它拼作“lusers”）。 

      我们也知道，很多人只想使用我们编写的软件，对技术细节没什么兴趣。对多数人们而
      言，计算机不过是一个工具，一种达到目的的手段；他们有更重要的事情要做，有更重要
      的生活要过。我们明白这点，也并不奢望每个人都对另我们痴狂的技术问题有兴致。然
      而，我们回答问题的风格是针对这样一群人--他们有兴趣，并且愿意积极参与问题的解
      决。这点不会改变，也不应该改变；如果变了，我们将失去我们引以为傲的效率。 

      我们在很大程度上属于志愿者，从繁忙的生活中抽出时间来解惑答疑，而且时常被提问淹
      没。所以我们无情的滤掉一些话题，特别是抛弃那些看起来象失败者的家伙，以便更高效
      的利用时间来回答胜利者的问题。 

      如果你觉得我们过于傲慢的态度让你不爽，让你委屈，不妨设身处地想想。我们并没有要
      求你向我们屈服--事实上，我们中的大多数人最喜欢公平交易不过了，只要你付出小小努
      力来满足最起码的要求，我们就会欢迎你加入到我们的文化中来。但让我们帮助那些不愿
      意帮助自己的人是没有意义的。如果你不能接受这种“歧视”，我们建议你花点钱找家商
      业公司签个技术支持协议得了，别向黑客乞求帮助。 

      如果你决定向我们求助，当然不希望被视为失败者，更不愿成为失败者中的一员。立刻得
      到有效答案的最好方法，就是象胜利者那样提问--聪明、自信、有解决问题的思路，只是
      偶尔在特定的问题上需要获得一点帮助。 

      （欢迎对本指南提出改进意见。任何建议请E-mail至esr@thyrsus.com，然而请注意，本
      文并非网络礼节的通用指南，我通常会拒绝无助于在技术论坛得到有用答案的建议。） 
      （当然，如果你写中文，最好还是寄到DHGrand@hotmail.com;-） 

      ======== 
      提问之前 
      ======== 

      在通过电邮、新闻组或者聊天室提出技术问题前，检查你有没有做到： 
      1. 通读手册，试着自己找答案。 
      2. 在FAQ里找答案（一份维护得好的FAQ可以包罗万象:）。 
      3. 在网上搜索（个人推荐google~）。 
      4. 向你身边精于此道的朋友打听。 


      当你提出问题的时候，首先要说明在此之前你干了些什么；这将有助于树立你的形象：你
      不是一个妄图不劳而获的乞讨者，不愿浪费别人的时间。能说明你从这些操作中学到了什
      么就更好了。如果提问者能从答案中学到东西，我们更乐于回答他的问题。 

      周全的思考，准备好你的问题，草率的发问只能得到草率的回答，或者根本得不到任何答
      案。越表现出在寻求帮助前为解决问题付出的努力，你越能得到实质性的帮助。 

      小心别问错了问题。如果你的问题基于错误的假设，普通黑客（J. Random Hacker）通
      常会用无意义的字面解释来答复你，心里想着“蠢问题...”，希望着你会从问题的回答
      （而非你想得到的答案）中汲取教训。 

      决不要自以为够资格得到答案，你没这种资格。毕竟你没有为这种服务支付任何报酬。你
      要自己去“挣”回一个答案，靠提出一个有内涵的，有趣的，有思维激励作用的问题--一
      个对社区的经验有潜在贡献的问题，而不仅仅是被动的从他人处索要知识--去挣到这个答
      案。 

      另一方面，表明你愿意在找答案的过程中做点什么，是一个非常好的开端。“谁能给点提
      示？”、“我这个例子里缺了什么？”以及“我应该检查什么地方？”比“请把确切的过
      程贴出来”更容易得到答复。因为你显得只要有人指点正确的方向，你就有完成它的能力
      和决心。 

      ======== 
      怎样提问 
      ======== 

      ------------ 
      谨慎选择论坛 
      ------------ 

      小心选择提问的场合。如果象下面描述的那样，你很可能被忽略掉或者被看作失败者： 
      1. 在风马牛不相及的论坛贴出你的问题 
      2. 在探讨高级技巧的论坛张贴非常初级的问题；反之亦然 
      3. 在太多的不同新闻组交叉张贴 

      黑客们通常砍掉问错地方的问题，以保护自己的社区不被大量无关帖子淹没。你不会希望
      自己的帖子被这样砍掉吧。 

      总的说来，问题发到精心挑选的公众论坛，比发到封闭的小圈子更容易得到有用的答案。
      这一现象有多种原因，其中之一是公众论坛有更多潜在的问题回答者；另一个原因是公众
      论坛有更多的听众。黑客们更愿意让尽量多的人--而非有限的一两个--从回答中受益。 

      ---------------- 
      尽量使用邮件列表 
      ---------------- 

      如果某项目有自己的开发邮件列表，要把问题发到这个邮件列表而不是某个开发者，即使
      你很清楚谁最能回答你的问题。仔细查看项目文档和项目主页，找到这个项目的邮件列表
      地址，这样做的理由有四： 
      1. 任何值得问某位开发者的好问题，都值得向整个开发团体提出。反之，若你认为这个
      问题不值得在邮件列表中提起，就没有理由用它来骚扰任何一位开发者。 
      2. 在邮件列表提问可以分担开发者的工作量。某位开发者（尤其当他是项目负责人的情
      况下），可能忙得没时间回答你的问题。 
      3. 大多数邮件列表都有历史存档，而且都能在搜索引擎中检索到。人们可以从中找到你
      的问题和答案，不用一遍又一遍在列表中发问。 
      4. 如果某个问题经常被提出，开发者可以据此改进文档或改进软件，以减少用户的困
      惑。而如果问题总在私下提出，就不会有人对此有整体上的把握了。 

      如果你找不到项目的邮件列表地址，只能看到项目维护者的，那就写给维护者吧。在这种
      情况下，也别以为邮件列表并不存在。在你的信中写明你已尽力寻找，仍无法找到邮件列
      表。另外表明你不介意将此消息转给他人。（大多数人认为私信就应该是私下的，即使并
      没有什么可保密的内容。允许你的消息被转寄给他人，给了收信者一种处理你邮件的选
      择。） 


      ---------------------------- 
      用辞贴切，语法正确，拼写无误 
      ---------------------------- 

      我们从经验中发现，粗心的写作者通常也是马虎的思考者（我敢打包票）。回答粗心大意
      者的问题很不值得，我们宁愿把时间耗在别处。 

      因此，明确充分表述你的问题非常重要。如果你嫌这样做麻烦，我们也会懒得搭理你。注
      意推敲你的用辞，不一定要用呆板正式的语言--事实上，黑客文化的价值观是不拘小节。
      准确的运用俚语和富有幽默感的语言，但别乱用；一定要能表明你在思考，在关注。 


      正确的拼写，标点符号和大小写很重要。别把“its”和“it's”或者“loose”和
      “lose”搞混淆了。别用全部大写的形式，这被视为粗鲁的大声叫嚷（全都用小写也好不
      到哪儿去，因为这会给阅读带来困难。Alan Cox可以用全部小写，但你不行）。 


      更一般的说，如果你的提问写得象个半文盲，你很有可能被忽视。如果写得象一个窥客
      （破解爱好者）或者灰客（只会用现成工具的捣乱者）绝对是自己找死，保证你除了无情
      的抵制什么也得不到（或者，最好的结局是得到一大堆挖苦嘲笑的“帮助”）。 

      如果你在使用非母语的论坛提问，你可以犯点拼写和语法上的小错--但决不能在思考上马
      虎（没错，我们能弄清两者的分别）。另外，除非你确切知道你的回答者会使用什么语
      言，否则请用英文。匆匆忙忙的黑客往往简单的跳过他们看不懂的问题，而英文是网络上
      的工作语言。用英文可以降低你的问题未被阅读即遭抛弃的风险。 

      ------------------ 
      用易读格式发送问题 
      ------------------ 

      如果人为造成你的提问难以阅读和理解，将会更容易被人忽略。因此你要： 
      1. 使用纯文本邮件，不要使用HTML（关掉HTML并不难）。 
      2. 通常可以附加MIME附件，但一定要有真正的内容（例如附加的源文件或者补丁），而
      不仅仅是你的邮件客户端产生的文件模板（例如你邮件的一份拷贝）。 
      3. 不要把所有问题放在不停换行的一整段中。（这将让答复的人难于回答其中一部分问
      题，即使能回答所有问题，我也更希望条理清楚的一个一个来:）。很可能收件人只能在
      80个字符宽度的文本显示器上读信，因此要相应的把行环绕模式设在80字符以内。 
      4. 不要在英文论坛使用MIME Quoted-Printable编码发送；这种编码格式对ASCII码不
      能表达的语言来说是非常必要的，但很多邮件代理不支持它，这时，满篇的“=20”符号
      把文字分割开，既难看，又分散注意力。 

      5. 永远不要指望黑客会乐于阅读封闭所有权的文件格式，例如萎软的Word格式。多数黑
      客对此的反应就象你在门口的阶梯上堆满热烘烘的猪粪（意即谁也不会踏进你的门--译者
      注）。 

      6. 如果你通过一台安装Windows的电脑发送邮件，关闭萎软愚蠢的“智能引用”功能。这
      能使你免于在邮件中夹带垃圾字符。 

      ---------------------------- 
      使用含义丰富，描述准确的标题 
      ---------------------------- 

      在邮件列表或者新闻组中，大约50字以内的主题标题是抓住资深专家注意力的黄金时机。
      别用喋喋不休的“帮帮忙”（更别说“救命啊！！！！！”这样让人反感的话）来浪费这
      个机会。不要妄想用你的痛苦程度来打动我们，别用空格代替问题的描述，哪怕是极其简
      短的描述。 

      蠢问题： 
      救命啊！我的膝上机不能正常显示了！ 

      聪明问题： 
      XFree86 4.1下鼠标光标变形，Fooware MV1005的显示芯片。 

      如果你在回复中提出问题，记得要修改内容标题，表明里面有一个问题。一个看起来象
      “Re：测试”或者“Re：新bug”的问题很难引起足够重视。另外，引用并删减前文的内
      容，给新来的读者留下线索。 

      ------------------ 
      精确描述，信息量大 
      ------------------ 

      1. 谨慎明确的描述症状。 
      2. 提供问题发生的环境（机器配置、操作系统、应用程序以及别的什么）。 
      3. 说明你在提问前是怎样去研究和理解这个问题的。 
      4. 说明你在提问前采取了什么步骤去解决它。 
      5. 罗列最近做过什么可能有影响的硬件、软件变更。 

      尽量想象一个黑客会怎样反问你，在提问的时候预先给他答案。 

      Simon Tatham写过一篇名为《如何有效的报告Bug》的出色短文。强力推荐你也读一读。


      -------- 
      话不在多 
      -------- 

      你需要提供精确有效的信息。这并不是要求你简单的把成吨的出错代码或者数据完全转储
      摘录到你的提问中。如果你有庞大而复杂的测试条件，尽量把它剪裁得越小越好。 

      这样做的用处至少有三点。第一，表现出你为简化问题付出了努力，这可以使你得到回答
      的机会增加；第二，简化问题使你得到有用答案的机会增加；第三，在提炼你的bug报告
      的过程中，也许你自己就能找出问题所在或作出更正。 

      ------------------ 
      只说症状，不说猜想 
      ------------------ 

      告诉黑客们你认为问题是怎样引起的没什么帮助。（如果你的推断如此有效，还用向别人
      求助吗？），因此要确信你原原本本告诉了他们问题的症状，不要加进你自己的理解和推
      论。让黑客们来诊断吧。 

      蠢问题： 
      我在内核编译中一次又一次遇到SIG11错误，我怀疑某条飞线搭在主板的走线上了，这种
      情况应该怎样检查最好？ 

      聪明问题： 
      我自制的一套K6/233系统，主板是FIC-PA2007 （VIA Apollo VP2芯片组），256MB
      Corsair PC133 SDRAM，在内核编译中频频产生SIG11错误，从开机20分钟以后就有这种
      情况，开机前20分钟内从没发生过。重启也没有用，但是关机一晚上就又能工作20分钟。
      所有内存都换过了，没有效果。相关部分的典型编译记录如下...。 

      ------------------ 
      按时间顺序列出症状 
      ------------------ 

      对找出问题最有帮助的线索，往往就是问题发生前的一系列操作，因此，你的说明应该包
      含操作步骤，以及电脑的反应，直到问题产生。在命令行操作的情况下，保存一个操作记
      录（例如使用脚本工具），并且引用相关的大约20条命令会大有帮助。 

      如果崩溃的程序有诊断选项（例如用-v转到详尽模式），试着仔细考虑选择选项以在操作
      记录中增加有用的调试信息。 

      如果你的说明很长（超过四个段落），在开头简述问题会有所帮助，接下来按时间顺序详
      述。这样黑客们就知道该在你的说明中找什么。 

      -------------- 
      别要求私下答复 
      -------------- 

      黑客们认为解决问题应该有公开、透明的流程。只要任何更有见地的人注意到答案的不完
      善或者不正确，这个最初的答案就可以和应该得到纠正。同时，通过能力和知识被大家注
      意，被大家接受，回答问题者得到了应有的奖励。 

      如果你要求对方私下回答你，这既破坏了整个流程，也破坏了奖励制度。别提这要求，这
      是回答者的权利，由他来选择是否私下答复--如果他选择这样做，通常是因为他认为这个
      答案过于显而易见或者有不良的公开影响，别人不会感兴趣。 

      只有一种有限的例外：如果你预计将收到大量雷同的答复，你可以说：“把答案寄给我，
      由我来汇总吧。”将邮件列表或者新闻组从大量重复的帖子中打救出来是很有君子之风的
      --但请记住，履行自己关于汇总的承诺。 

      -------------- 
      明白你想问什么 

      -------------- 

      漫无边际的提问近乎无休无止的时间黑洞。最能给你有用答案的人也正是最忙的人（他们
      忙是因为要亲自完成大部分工作）。这样的人对无节制的时间黑洞不太感冒，因此也可以
      说他们对漫无边际的提问不大感冒。 

      如果你明确表述需要回答者做什么（提供建议，发送一段代码，检查你的补丁或是别
      的），就最有可能得到有用的答案。这会定出一个时间和精力的上限，便于回答者集中精
      力来帮你，这很凑效。 

      要理解专家们生活的世界，要把专业技能想象为充裕的资源，而回复的时间则是贫乏的资
      源。解决你的问题需要的时间越少，越能从忙碌的专家口中掏出答案。 

      因此，优化问题的结构，尽量减少专家们解决它所需要的时间，会有很大的帮助--这通常
      和简化问题有所区别。因此，问“我想更好的理解X，能给点提示吗？”通常比问“你能
      解释一下X吗？”更好。如果你的代码不能工作，问问它有什么地方不对，比要求别人替
      你修改要明智得多。 


      ------------------------ 
      别问应该自己解决的问题 
      ------------------------ 

      黑客们总是善于分辨哪些问题应该由你自己解决；因为我们中的大多数都曾自己解决这类
      问题。同样，这些问题得由你来搞定，你会从中学到东西。你可以要求给点提示，但别要
      求得到完整的解决方案。 

      ---------------- 
      去除无意义的疑问 
      ---------------- 

      别用无意义的话结束提问，例如“有人能帮我吗？”或者“有答案吗？”。首先：如果你
      对问题的描述不很合适，这样问更是画蛇添足。其次：由于这样问是画蛇添足，黑客们会
      很厌烦你--而且通常会用逻辑上正确的回答来表示他们的蔑视，例如：“没错，有人能帮
      你”或者“不，没答案”。 

      ---------------------------- 
      谦逊绝没有害处，而且常帮大忙 
      ---------------------------- 

      彬彬有礼，多用“请”和“先道个谢了”。让大家都知道你对他们花费时间义务提供帮助
      心存感激。 

      实话实说，虽然这不象合乎语法、清楚准确的描述，避免私有格式等等那么重要（也不能
      用来替代它们）；黑客一般更喜欢直接了当然而技术上敏锐的bug报告，而不是彬彬有礼
      的废话（如果这让你迷惑不解，请记住，我们衡量一个问题价值的标准是：它能让我们学
      会多少）。 

      然而，如果你有很多问题无法解决，礼貌将会增加你得到有用答案的机会。 

      （我们注意到，自从本指南发布后，从资深黑客处得到的唯一严重缺陷反馈，就是对预先
      道谢这一条。一些黑客觉得“先谢了”的言外之意是过后就不会再感谢任何人了。我们的
      建议是：都道谢。） 

      ------------------------ 

      问题解决后，加个简短说明 
      ------------------------ 

      问题解决后，向所有帮助过你的人发个说明，让他们知道问题是怎样解决的，并再一次向
      他们表示感谢。如果问题在新闻组或者邮件列表中引起了广泛关注，应该在那里贴一个补
      充说明。 

      补充说明不必很长或是很深入；简单的一句“你好，原来是网线出了问题！谢谢大家
      --Bill”比什么也不说要强。事实上，除非结论真的很有技术含量，否则简短可爱的小结
      比长篇学术论文更好。说明问题是怎样解决的，但大可不必将解决问题的过程复述一遍。


      除了表示礼貌和反馈信息以外，这种补充有助于他人在邮件列表/新闻组/论坛中搜索对你
      有过帮助的完整解决方案，这可能对他们也很有用。 

      最后（至少？），这种补充有助于所有提供过帮助的人从中得到满足感。如果你自己不是
      老手或者黑客，那就相信我们，这种感觉对于那些你向他们求助的导师或者专家而言，是
      非常重要的。问题久拖未决会让人灰心；黑客们渴望看到问题被解决。好人有好报，满足
      他们的渴望，你会在下次贴出新问题时尝到甜头。 

      ============ 
      如何理解答案 
      ============ 

      -------------------- 
      RTFM和STFW：别烦我啦 
      -------------------- 

      有一个古老而神圣的传统：如果你收到“RTFM （Read The Fucking Manual）”的回
      复，回答者认为你应该去读TMD手册。当然，基本上他是对的，你应该读一读。 

      RTFM有一个年轻的亲戚。如果答案是“STFW （Search The Fucking Web）”，回答者
      认为你应该到TMD的网上去搜索。基本上，他也是对的，你就去找吧。 

      通常，用这两句之一回答你的人会给你一份包含你需要内容的手册或者一个网址，而且他
      们打这些字的时候正在阅读着。这些答复意味着回答者认为(1). 你需要的信息非常容易
      获得；(2). 你自己去搜索这些信息比灌给你能让你学到更多。 

      别为这个而不爽；依照黑客的标准，他没有对你的要求视而不见，已经能大致能表示对你
      的关注。你应该对他祖母般的慈祥表示感谢。 

      ---------- 
      还是不懂:( 
      ---------- 

      如果你不是很理解答案，别立刻要求对方解释。象你以前试着自己解决问题时那样（利用
      手册，FAQ，网络，身边的高手），去理解它。如果你真的需要对方解释，记得表现出你
      已经学到了点什么。 

      比方说，如果我回答你：“看来似乎是zEntry被阻塞了；你应该先清除它。”，然后： 

      一个很糟的后续问题：“zEntry是什么？” 

      聪明的问法应该是这样：“哦~我看过帮助了:)但是只有-z和-p两个参数中提到了
      zEntry:(而且还都没有清楚的解释:&lt;你是指这两个中的哪一个吗？还是我看漏了什么？”


      -------- 
      面对无礼 
      -------- 

      黑客圈子里很多貌似粗鲁的言行并非有意冒犯。更恰当的说，这是直率、不说废话的沟通
      方式的产物，这种沟通方式源于人们关注问题的解决--多过让人感受温暖亲情然而却依旧
      糊里糊涂--的天性。 

      如果你觉得受到粗鲁的对待，请保持冷静。如果真有人表现粗野，通常会有列表/新闻组/
      论坛的长辈找他谈心，如果没有这样，而你又大发脾气，则很可能对方的言行是黑客社区
      行为规范许可内，而你被认为是有过错的。这会不利于你得到信息或者帮助。 

      另一方面，你偶尔也会无缘无故有粗野的言行和心态。上述现象的另一面是，人们允许狠
      狠打击真正的冒犯者，用尖刻的言语剖析他们的不当言行。如果你真决定这样做，先仔细
      又仔细的掂量一下你自己的分量。合理的粗鲁与发动一场无意义的论战之间只隔了一条细
      细的线，冒冒失失撞上去的黑客不在少数；如果你是新手或者门外汉，不犯这种错的机会
      是很渺茫的。如果你想得到信息而不是来胡闹，别冒险回复，最好把手从键盘上拿开。 

      （有些人声称多数黑客有孤僻症或者社交障碍综合征的轻度症状，而且确实缺少部分有助
      “常人”进行社交行为的脑组织结构。这也许是真的，也许不是。如果你自己不是黑客，
      那么，把我们想象成脑部有缺陷的人有助你面对我们的古怪。有话直说，我们无所谓；我
      们乐于按自己的想法生活，而且总是对医学概念持相当怀疑的态度。） 

      在下一节里，我们将谈论另一个话题；当你行差踏错时可能遇到的“无礼”。 

      ================ 
      决不要象个失败者 
      ================ 

      很有可能，你在黑客社区的论坛会受到很多公开的攻击--用本文提到的各种方式或类似的
      方法，而且很可能会有各式各样的旁敲侧击来告诉你你有多讨厌。 

      如果噩梦成真，你能做的最糟的事就是为此发牢骚，抱怨受到人身攻击，要求对方道歉，
      尖叫，屏住呼吸，威胁要控诉对方，向他老板告状，不掀起马桶座圈，等等等等。然而，
      你应该这样： 

      由它去吧，这没什么大不了的。实际上这么做是恰当的和有益的（主要是有利身心健
      康:）。 

      社区的规范不靠社区，而是靠积极推行它们的人们来维护，这种维护是公开的，显而易见
      的。别抱怨说一切批评都应该通过私信传送，它本来就不该那样。当别人指出你的话有错
      误，或者他有不同观点的时候，坚持认为他在羞辱你是没有用的。这些都是失败者的态
      度。 

      有那么一些黑客论坛，出于对高度自谦的误解，禁止参与者张贴专给人找茬的帖子，而且
      被告知“如果不愿帮助用户，那就闭嘴。”，他们认为，引开参与者的话题，只会使得他
      们陶醉在毫无意义的喋喋不休中，从而失去了技术论坛的意义。 

      夸张的“友善”（以那种方式）还是有用的帮助：你自己选择吧。 

      记住：当黑客说你很烦人，（无论用多么粗暴的语言）警告你别再那样做了，他的本意并
      非是针对(1)你，以及(2)他的社区。他本来可以轻易的忽略你，把你从他的视线中抹去。
      如果你无法接受要向他表示感激，至少应该表现出你的气度，别抱怨，别期望只因为你是
      新人，你有戏剧般的敏感脆弱的神经和自封的权利，而受到易碎玩偶般的特别对待。 

      ========== 
      三思而后问 
      ========== 

      以下是几个经典蠢问题，以及黑客在拒绝回答时的心中所想： 

      问题：我能在哪找到X程序？ 
      问题：我的程序/配置/SQL申明没有用 
      问题：我的Windows有问题，你能帮我吗？ 
      问题：我在安装Linux（或者X）时有问题，你能帮我吗？ 
      问题：我怎么才能破解root帐号/窃取OP特权/读别人的邮件呢？ 

      提问：我能在哪找到X程序？ 
      回答：就在我找到它的地方啊蠢货--搜索引擎的那一头。天呐！还有人不会用Google吗？


      提问：我的程序（配置、SQL申明）没有用 
      回答：这不算是问题吧，我对找出你的真正问题没兴趣--如果要我问你二十个问题才找得
      出来的话--我有更有意思的事要做呢。在看到这类问题的时候，我的反应通常不外如下三
      种： 
      1. 你还有什么要补充的吗？ 
      2. 真糟糕，希望你能搞定。 
      3. 这跟我有什么鸟相关？ 

      提问：我的Windows有问题，你能帮我吗？ 
      回答：能啊，扔掉萎软的垃圾，换Linux吧。 

      提问：我在安装Linux（或者X）时有问题，你能帮我吗？ 
      回答：不能，我只有亲自在你的电脑上动手才能找到毛病。还是去找你当地的Linux用户
      组寻求手把手的指导吧（你能在这儿找到用户组的清单）。 

      提问：我怎么才能破解root帐号/窃取OP特权/读别人的邮件呢？ 
      回答：想要这样做，说明你是个卑鄙小人；想找个黑客帮你，说明你是个白痴！ 

      ============== 
      好问题，坏问题 
      ============== 

      最后，我举一些例子来说明，怎样聪明的提问；同一个问题的两种问法被放在一起，一种
      是愚蠢的，另一种才是明智的。 

      蠢问题：我可以在哪儿找到关于Foonly Flurbamatic的资料？ 
      这种问法无非想得到“STFW”这样的回答。 

      聪明问题：我用Google搜索过“Foonly Flurbamatic 2600”，但是没找到有用的结
      果。谁知道上哪儿去找对这种设备编程的资料？ 
      这个问题已经STFW过了，看起来他真的遇到了麻烦。 

      蠢问题：我从FOO项目找来的源码没法编译。它怎么这么烂？ 
      他觉得都是别人的错，这个傲慢自大的家伙:( 

      聪明问题：FOO项目代码在Nulix 6.2版下无法编译通过。我读过了FAQ，但里面没有提到
      跟Nulix有关的问题。这是我编译过程的记录，我有什么做得不对的地方吗？ 
      他讲明了环境，也读过了FAQ，还指明了错误，并且他没有把问题的责任推到别人头上，
      这个家伙值得留意。 

      蠢问题：我的主板有问题了，谁来帮我？ 
      普通黑客对这类问题的回答通常是：“好的，还要帮你拍拍背和换尿布吗？” ，然后按
      下删除键。 

      聪明问题：我在S2464主板上试过了X、Y和Z，但没什么作用，我又试了A、B和C。请注意
      当我尝试C时的奇怪现象。显然边带传输中出现了收缩，但结果出人意料。在多处理器主
      板上引起边带泄漏的通常原因是什么？谁有好主意接下来我该做些什么测试才能找出问
      题？ 
      这个家伙，从另一个角度来看，值得去回答他。他表现出了解决问题的能力，而不是坐等
      天上掉答案。 

      在最后一个问题中，注意“告诉我答案”和“给我启示，指出我还应该做什么诊断工作”
      之间微妙而又重要的区别。 

      事实上，后一个问题源自于2001年8月在Linux内核邮件列表上的一个真实的提问。我
      （Eric）就是那个提出问题的人。我在Tyan S2464主板上观察到了这种无法解释的锁定
      现象，列表成员们提供了解决那一问题的重要信息。 

      通过我的提问方法，我给了大家值得玩味的东西；我让人们很容易参与并且被吸引进来。
      我显示了自己具备和他们同等的能力，邀请他们与我共同探讨。我告诉他们我所走过的弯
      路，以避免他们再浪费时间，这是一种对他人时间价值的尊重。 

      后来，当我向每个人表示感谢，并且赞赏这套程序（指邮件列表中的讨论--译者注）运作
      得非常出色的时候，一个Linux内核邮件列表（lkml）成员表示，问题得到解决并非由于
      我是这个列表中的“名人”，而是因为我用了正确的方式来提问。 

      我们黑客从某种角度来说是拥有丰富知识但缺乏人情味的家伙；我相信他是对的，如果我
      象个乞讨者那样提问，不论我是谁，一定会惹恼某些人或者被他们忽视。他建议我记下这
      件事，给编写这个指南的人一些指导。 

      ================ 
      找不到答案怎么办 
      ================ 

      如果仍得不到答案，请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答
      案罢了。没有回应不代表你被忽视，虽然不可否认这种差别很难区分。 


      总的说来，简单的重复张贴问题是个很糟的想法。这将被视为无意义的喧闹。 

      你可以通过其它渠道获得帮助，这些渠道通常更适合初学者的需要。 

      有许多网上的以及本地的用户组，由狂热的软件爱好者（即使他们可能从没亲自写过任何
      软件）组成。通常人们组建这样的团体来互相帮助并帮助新手。 

      另外，你可以向很多商业公司寻求帮助，不论公司大还是小（Red Hat和LinuxCare就是
      两个最常见的例子）。别为要付费才能获得帮助而感到沮丧！毕竟，假使你的汽车发动机
      汽缸密封圈爆掉了--完全可能如此--你还得把它送到修车铺，并且为维修付费。就算软件
      没花费你一分钱，你也不能强求技术支持总是免费的。 

      对大众化的软件，就象Linux之类而言，每个开发者至少会有上万名用户。根本不可能由
      一个人来处理来自上万名用户的求助电话。要知道，即使你要为帮助付费，同你必须购买
      同类软件相比，你所付出的也是微不足道的（通常封闭源代码软件的技术支持费用比开放
      源代码软件要高得多，而且内容也不那么丰富）。 


 
<!-- 下面不要动 -->
</FONT><PRE></PRE></PRE></TD></TR>
<TR>
<TD align=right>&nbsp;</TD></TR>
<TR>
<TD><A href="http://www.linuxforum.net/">中国Linux论坛</A> 版权所有 </TD></TR></TBODY></TABLE></CENTER>
<P><BR><BR><BR>&nbsp;</P>
<HR>

<P><BR>&nbsp;</P>
<CENTER>Copyright 1999，2000, 2001 China Linux Forum</CENTER>
<P><BR>&nbsp;</P></DIV></FONT></H3></CENTER>]]></description>
</item><item>
<title><![CDATA[关于在.net中使用winpcap的环境配置]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=13558</link>
<author>binaryluo</author>
<pubDate>2006/4/17 22:45:54</pubDate>
<description><![CDATA[
<P><A><FONT size=2>　</FONT></A><FONT size=2>因为有多位网友询问过如何在.net下配置winpcap环境，特请求网友风雷提供他在.net下使用winpcap的环境配置步骤。为了方便各位需要在.net下配置winpcap的网友，我代他将该文发表在我的blog上。在此特别感谢风雷的共享精神。&nbsp;&nbsp;&nbsp; </FONT></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid"><FONT size=2>作者：风雷</FONT> 
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 通过pcap开发包开发出常用的网络捕获工具已经是大多数相关开发人士的首选了，不过大多数朋友是刚转入.net平台，在相同文件的情况下，.net平台和普通vc++6.0的平台编译结果是完全不一样的。总结起来主要是.net安装目录下库文件与vc的差异造成的。由于一个竞赛活动，我需要写一个网络管理程序，本来没用过.net和c++，硬着头皮花了一周时间学了一下，目前正在编写程序中。这里只能讲解一下.net平台中的设置方法，具体编程的问题还需要各位多多指点，下面就是用.net编译pcap函数库程序的方法：</FONT></P>
<P><BR><FONT size=2>1. 安装winpcap开发包。</FONT></P>
<P><FONT size=2>2.&nbsp;最好在你开发项目所在的文件夹中新建一个inc文件夹，把vc++6.0安装文件夹中D:\Program Files\VC++\VC98\Include下的.h文件都拷贝过去，再把pcap安装目录下的相关.h文件也全部拷贝过去。</FONT></P>
<P><FONT size=2>3.&nbsp;打开.net平台，也就是visual studio，打开项目-属性。</FONT></P>
<P><FONT size=2>4.&nbsp;选择配置属性下的c/c++---常规，找到右边的附加包含目录（也就是第一项），把你刚才所建的inc文件夹的路径包含进去。实际上你直接包含D:\Program Files\VC++\VC98\Include以及pcap安装目录下的相关.h文件所在位置，也可以，我就是图个方便。</FONT></P>
<P><FONT size=2>5.&nbsp;然后找到配置属性下链接—输入这项，右边第一项是附加以来项，要把wpcap.lib Ws2_32.lib这两个lib包含进去。这里就是用来包含lib的，其他你需要的lib也在这里包含。</FONT></P>
<P><FONT size=2>6.&nbsp;如果你的程序需要在cmd下通过参数运行，想直接在.net中调试，怎么做到自动加载参数呢？（就是argv）找到配置属性下的调试一项，右边第二行就是命令参数，第三行是你所用资源文件的目录。这样，通过studio调试时你就能模拟cmd的真实环境了。</FONT></P>
<P><FONT size=2>7.&nbsp;如果抱错是说找不到外部变量什么的，肯定是相关lib文件没有包含。</FONT></P>
<P><FONT size=2>8. 有别的什么问题请直接邮件联系我，lk_517#163.com。</FONT><FONT size=2>我的blog:http://likunarmstrong.bokee.com/上有更加详细的联系方式。<BR></FONT></P></DIV>
<P><FONT size=2><BR></FONT>&nbsp;</P>]]></description>
</item><item>
<title><![CDATA[关于Winpcap和NDIS数据包的问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=13040</link>
<author>binaryluo</author>
<pubDate>2006/3/30 17:41:26</pubDate>
<description><![CDATA[<A></A>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">问题一：</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Winpcap</FONT></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">捕获到的数据包是什么？</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">pcap_open()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数的第二个参数</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">snaplen</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示的是需要保存的数据包的长度，对于被过滤器接收到的每一个数据包，仅仅只有开始的‘</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">snaplen</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">’个字节被保存到缓冲区然后被传递给用户应用程序。例如，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">snaple</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等于</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">100</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">意味着仅仅保存每一个数据包开始的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">100</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个字节。在某些操作系统中（例如</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">xBSD</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Win32</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">），数据包驱动程序可以被配置了只捕获数据包的首部：这样可以减少要拷贝的数据量从而提高抓包的效率。如果想要获得完整的数据包，可以把</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">snaplen</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">赋值为</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">65535</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，因为</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">65535</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">远远大于我们所遇到的最大的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">MTU</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。下图（截自《</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">TCP/IP</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">详解卷一：协议》）列出了最常见的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">MTU</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><o:wrapblock><?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id=_x0000_s1026 style="MARGIN-TOP: 4.25pt; Z-INDEX: 1; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 281.25pt; POSITION: absolute; HEIGHT: 148.5pt; TEXT-ALIGN: left; mso-position-horizontal: center" type="#_x0000_t75"><FONT size=2><v:imagedata o:title="" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.emz"></v:imagedata><?xml:namespace prefix = w ns = "urn:schemas-microsoft-com:office:word" /><w:wrap type="topAndBottom"></w:wrap></FONT></v:shape></o:wrapblock><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006330175024513.JPG" border=0><BR style="mso-ignore: vglayout" clear=all><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">pcap_dispatch()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">pcap_loop()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都是捕获数据包的函数。它们的功能非常相似，只是返回的时机不同，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">pcap_ dispatch()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">pcap_handler()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中的第二个参数</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">struct pcap_pkthdr *pkt_header</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是与抓包驱动程序相关的一些头部信息，但它不是协议头。第三个参数</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">const u_char *pkt_data</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是指向数据包的指针，包括协议头。如下图（截自</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">文档）所示：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><o:wrapblock><v:shape id=_x0000_s1027 style="MARGIN-TOP: 7.35pt; Z-INDEX: 2; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 264pt; POSITION: absolute; HEIGHT: 219.75pt; TEXT-ALIGN: left; mso-position-horizontal: center" type="#_x0000_t75" alt="stats_wpcap.gif"><FONT size=2><v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image003.gif" o:href="file:///D:\binary\grd_prj\src\WpdPack\docs\html\stats_wpcap.gif"></v:imagedata><w:wrap type="topAndBottom"></w:wrap></FONT></v:shape></o:wrapblock><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/200633017536439.JPG" border=0><BR style="mso-ignore: vglayout" clear=all><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">因此表明</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">捕获到的数据包就是一些字节流，该字节流以一个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">MTU</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的实际大小作为一个数据包，所以前面如果在</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">pcap_open()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">里设置了</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">snaplen</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">65535</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就可以保证以</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">65535</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节为一个数据包的大小，如果</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">MTU</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">小于</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">65535</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，多出来的字节将添</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">0</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（这里我已经用</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">抓获数据包分析过）。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p><FONT face="Times New Roman" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总结：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">先回顾下</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的内部结构图（截自</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">文档）：</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006330175410606.GIF" border=0></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供了两个不同的库：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">packet.dll</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">wpcap.dll</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">前者提供了一个底层</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">API</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，伴随着一个独立于</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Microsoft</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">操作系统的编程接口，这些</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">API</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以直接用来访问驱动的函数；后者导出了一组更强大的与</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">libpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一致的高层抓包函数库（</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">capture primitives</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">），这些函数使得数据包的捕获以一种与网络硬件和操作系统无关的方式进行</SPAN></FONT><o:wrapblock><v:shape id=_x0000_s1028 style="MARGIN-TOP: 7.95pt; Z-INDEX: 3; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 210pt; POSITION: absolute; HEIGHT: 266.25pt; TEXT-ALIGN: left; mso-position-horizontal: center; mso-position-horizontal-relative: text; mso-position-vertical-relative: text" type="#_x0000_t75" alt=""><FONT face="Times New Roman"><FONT size=2> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image004.gif" o:href="file:///D:\binary\grd_prj\src\WpdPack\docs\html\internals-arch.gif"></v:imagedata><w:wrap type="topAndBottom"></w:wrap></FONT></FONT></v:shape></o:wrapblock><BR style="mso-ignore: vglayout" clear=all><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Packet.dll</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是一个相对于</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动的用户应用程序，就是来使用</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供的功能的；</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">wpcap.dll</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的接口跟</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">libpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是一样的。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Winpcap</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">捕获到的数据包是什么还是依赖于</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的库函数。不过根据</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">发送的数据格式可以判断它捕获到的数据包应该也是字节流，因为</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">允许发送的数据包可以没有按照任何的协议进行封装，因为封装的工作是在应用程序里完成的，也就是说</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">根本不关心上层传下来的是什么，只要传下来就发送；按照发送数据包的思路推想接收数据包也应该是这样的，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NPF</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不关心接收到的是什么东西，反正它以你规定的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">snaplen</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为单位读取数据交给上层应用程序，由应用程序来判断该数据到底是怎么封装的，也就是</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Packet.dll</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或更上层应用程序。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p><FONT face="Times New Roman" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">问题二：</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Ndis</FONT></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">库函数从网卡拷贝过来的数据包是什么？</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据包被协议驱动分配的，填以数据，并且为了将这些数据发送出去而传递给更低层的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动。通常，协议驱动分配一个数据包并且把它传递给一个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NIC</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动，然后</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NIC</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动把接收到的数据拷贝到协议驱动所提供的数据包中。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供了分配和操作包装数据包结构体的函数。下图（截自</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">DDK</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）阐明了一个数据包的结构：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><o:wrapblock><v:shape id=_x0000_s1029 style="MARGIN-TOP: 5.4pt; Z-INDEX: 4; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 405pt; POSITION: absolute; HEIGHT: 240pt; TEXT-ALIGN: left; mso-position-horizontal: center" type="#_x0000_t75"><FONT size=2><v:imagedata o:title="Packet" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image005.jpg"></v:imagedata><w:wrap type="topAndBottom"></w:wrap></FONT></v:shape></o:wrapblock><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006330175553575.GIF" border=0><BR style="mso-ignore: vglayout" clear=all><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下面就讨论</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是如何用</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示网络上的数据包（</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Packet</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）。下面是一个简单的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">ICMP</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">“</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">ping</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">”数据包的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">16</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进制表示：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P><PRE><SPAN lang=EN-US style="FONT-SIZE: 10.5pt"><FONT face=宋体 size=2>000000: </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#Ethernet%20Header"><FONT face=宋体 size=2>00 A0 CC 63 08 1B 00 40 : 95 49 03 5F 08 00</FONT></A><FONT face=宋体 size=2> </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#IP%20Header"><FONT face=宋体 size=2>45 00</FONT></A><FONT face=宋体><FONT size=2> ...c...@.I._..E.<o:p></o:p></FONT></FONT></SPAN></PRE><PRE><SPAN lang=EN-US style="FONT-SIZE: 10.5pt"><FONT face=宋体 size=2>000010: </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#IP%20Header"><FONT face=宋体 size=2>00 3C 82 47 00 00 20 01 : 94 C9 C0 A8 01 20 C0 A8</FONT></A><FONT face=宋体><FONT size=2> .&lt;.G.. ...... ..<o:p></o:p></FONT></FONT></SPAN></PRE><PRE><SPAN lang=EN-US style="FONT-SIZE: 10.5pt"><FONT face=宋体 size=2>000020: </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#IP%20Header"><FONT face=宋体 size=2>01 40</FONT></A><FONT face=宋体 size=2> </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#IP%20Data"><FONT face=宋体 size=2>08 00 48 5C 01 00 : 04 00 61 62 63 64 65 66</FONT></A><FONT face=宋体><FONT size=2> .@..H\....abcdef<o:p></o:p></FONT></FONT></SPAN></PRE><PRE><SPAN lang=EN-US style="FONT-SIZE: 10.5pt"><FONT face=宋体 size=2>000030: </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#IP%20Data"><FONT face=宋体 size=2>67 68 69 6A 6B 6C 6D 6E : 6F 70 71 72 73 74 75 76</FONT></A><FONT face=宋体><FONT size=2> ghijklmnopqrstuv<o:p></o:p></FONT></FONT></SPAN></PRE><PRE><SPAN lang=EN-US style="FONT-SIZE: 10.5pt"><FONT face=宋体 size=2>000040: </FONT><A href="http://www.ndis.com/papers/ndispacket/ndispacket_decode.htm#IP%20Data"><FONT face=宋体 size=2>77 61 62 63 64 65 66 67 : 68 69</FONT></A><FONT face=宋体><FONT size=2><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>wabcdefghi......<o:p></o:p></FONT></FONT></SPAN></PRE>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">ping</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是由下面的命令来初始化的：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman"><FONT size=2>C:&gt; ping 192.168.1.64<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">并发送伴随着默认的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">32</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节数据的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">ICMP</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">响应请求。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">Ping</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据包的总长度是</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">74</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节。下图（截自</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman"><A href="http://www.ndis.com/papers/ndispacket/ndispacket1.htm">http://www.ndis.com/papers/ndispacket/ndispacket1.htm</A></FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）阐明了一个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用来表示被封装好的数据包数据的简单方式：</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN></FONT><o:wrapblock><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/200633017588936.GIF" border=0><v:shape id=_x0000_s1030 style="MARGIN-TOP: 2.25pt; Z-INDEX: 5; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 366.75pt; POSITION: absolute; HEIGHT: 198pt; TEXT-ALIGN: left; mso-position-horizontal: center" type="#_x0000_t75"><FONT size=2><v:imagedata o:title="simp_packet" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image006.gif"></v:imagedata><w:wrap type="topAndBottom"></w:wrap></FONT></v:shape></o:wrapblock><BR style="mso-ignore: vglayout" clear=all><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在这个简单的例子中，数据包数据的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">74</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个字节全都是在一片连续的空间内。用一句话对这个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可描述为：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">有一个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_BUFFER</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">链，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_BUFFER</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">描述了包含完整数据包数据的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">74</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节大小的虚拟存储空间。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下面这个图比上面那个图稍微复杂一点，它阐明了</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示封装好的数据包数据的另一种方式：</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN></FONT><o:wrapblock><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006330175835149.GIF" border=0><v:shape id=_x0000_s1031 style="MARGIN-TOP: 2.55pt; Z-INDEX: 6; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 366pt; POSITION: absolute; HEIGHT: 198pt; TEXT-ALIGN: left; mso-position-horizontal: center" type="#_x0000_t75"><FONT size=2><v:imagedata o:title="multi_packet" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image007.gif"></v:imagedata><w:wrap type="topAndBottom"></w:wrap></FONT></v:shape></o:wrapblock><BR style="mso-ignore: vglayout" clear=all><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在这个例子中数据包数据被存放在两个不连续的虚拟存储空间中。用一句话总结如下：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">有两个链在一起的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_BUFFER</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，第一个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_BUFFER</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示了包含以太帧头部的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">14</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节虚拟存储空间，第二个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_BUFFER</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表示以太帧的有效负载（数据）的</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">60</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字节虚拟存储空间。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">尽管上面两个图有助于理解如何使用一个</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，但是还必须注意一点这些结构体是透明的。我们不能直接访问结构体的这些域，只能通过</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">库提供的函数来访问它们。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供的用来检查</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_PACKET</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NDIS_BUFFER</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的函数很少，下面列举几个（详细信息看</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">DDK</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NdisQueryPacket</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NdisQueryBuffer</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NidsGetNextBuffer</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><FONT face="Times New Roman">NdisQueryBufferSafe</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p><FONT face="Times New Roman" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总结：</SPAN><SPAN lang=EN-US style="mso-bidi-font-size: 10.5pt"><o:p></o:p></SPAN></FONT></P><FONT size=2><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">网线上传输的是电信号，</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NIC</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的功能就是将这些电信号转化成计算机能够理解的二进制位串，而网卡驱动就是将这些连续的二进制位串进行整理，把它整理成</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NDIS_PACKET</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">这样的结构体，所以从网卡读数据包的时候读到的就是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NDIS_PAKCET</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">这种结构体。然后</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NDIS</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">提供了相应的函数来处理</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NDIS_PACKET</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">结构体，一个</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NDIS_PACKET</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">中的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">NDIS_BUFFER</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">组成的链表所指示的虚拟存储空间连接起来就是一个完整的数据帧。</SPAN></FONT>]]></description>
</item><item>
<title><![CDATA[从 do { } while (FALSE)  学到的]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=12576</link>
<author>binaryluo</author>
<pubDate>2006/3/15 16:10:52</pubDate>
<description><![CDATA[
<P><A><FONT size=2>　</FONT></A>&nbsp; <FONT size=2>昨天在看微软的一个示例代码的时候发现在代码里多处使用了下面的结构：</FONT></P>
<P><FONT size=2>do {</FONT></P>
<P><FONT size=2>.....</FONT></P>
<P><FONT size=2>} while (FALSE)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 看了以后很是纳闷——不要这个do－while循环，直接执行循环里面的内容有什么区别。跟几个同学讨论了也还是没有弄明白，但是又想微软怕不至于写这样多余的“垃圾”代码。今天无意在网上一搜，居然真相大白了，微软使用这样的永假循环果然是有原因的。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 下面是我找到的一篇讲述该问题的文章，写得很不错（这几天真是走运，不断遇到好文章^_^），贴出来供大家参考：</FONT></P>
<P><!--StartFragment --><FONT size=2>原文出处：</FONT><A href="http://www.d2school.com/bcyl/bhcpp/newls/ls11.htm#11.1.2"><FONT size=2>http://www.d2school.com/bcyl/bhcpp/newls/ls11.htm#11.1.2</FONT></A></P><FONT size=2>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
<H2><FONT size=2>第十一章　流程控制拾遗与混合训练</FONT></H2>
<P><FONT size=2>11.1 break</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.1.1 break的作用与用法</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.1.2 break 的一个“高级用法”</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.1.3 break 在for循环中的一点注意</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.1.4 多层循环中的break</FONT></P>
<P><FONT size=2>11.2 continue</FONT></P>
<P><FONT size=2>11.3 goto</FONT></P>
<P><FONT size=2>11.4 流程控制强化训练</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.4.1 求绝对值</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.4.2 判断用户输入字符的类型</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.4.3　等腰三角形图形的输出</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.4.4 输出正弦曲线图</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT><FONT size=2>11.4.5 标准体重计算程序</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>说“拾遗”，可能你会以为本章的内容不是重点？那可不是，流程控制的内容并不多，却支撑着所有程序的框架！所所有有关流程的内容都是基础加重点。只是本章中继续讲到一些关键字可以改变流程，但并不独自构成完整流程结构。</FONT></P>
<P><FONT size=2>另外，作为流程控制内容的结束章节，我们于最后安排了一些各流程混合使用的训练。</FONT><FONT size=2>　</FONT></P>
<H3><A name=11.1><FONT size=2>11.1</FONT></A><FONT size=2> break</FONT></H3>
<H4><A name=11.1.1><FONT size=2>11.1.1</FONT></A><FONT size=2> break的作用与用法</FONT><FONT size=2>　</FONT></H4>
<P><FONT size=2>循环就象绕圈子。比如，体育课，跑1200米，跑道一圈400米，所以我们要做的事就是一边跑一边在心里计数（当然要已数，否则老师万一少计一圈，我们可就玩完了），当计数到3圈时，“循环”结束。</FONT></P>
<P><FONT size=2>如果，我在跑步时不幸由于体力不支而晕倒……怎么办？</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>有两种办法，一种是在判断是否继续循环的条件中加入新增条件的判断：</FONT></P>
<P><FONT size=2>假设原来的循环表达为：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑完的圈数 &lt; 3)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑一圈……；</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>那么，加上附加条件后，循环表达为：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑完的圈数 &lt;3 &amp;&amp; 我还跑得好好的） //&amp;&amp; 就是"并且"，没忘吧？</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑一圈……</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>第二种方法是在循环中使用条件分支，在指定的条件成立时，中途跳出循环，用于实现跳出的关键字为：break。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑的圈数 &lt; 3 )</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑一圈……；</FONT><FONT size=2>&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>在循环中，每跑完一圈，都检查一下自已是否感觉不妙，如果是，则程序执行break,直接跳出while，而不管此时圈数是否到达3圈。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>还记得“小女孩买裙子”的故事吗？那时候，我们将“父母不给买小红裙 &amp;&amp; 我还没有哭累”作为循环继续的条件，如果使用break，则可以写成这样：</FONT></P>
<P><FONT size=2>while(父母不给买小红裙）</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 我哭；</FONT><FONT size=2>&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp; if(我哭累了）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; break;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>在循环中，“我”每哭一次，都想想是否累了，如果是，则程序执行break，直接跳出while，而不管此时爸妈是否已经买了我的裙。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>通过这两个例子，你应该注意到了，如果要用break，则if的条件（也就是要执行break分支的条件），正好是把原来放在循环判断中的条件反正过来。比如，原来是判断“我还跑得好好的”，现在则是判断“我身体感觉不妙”；原来是判断“我还没有哭累”，现在是判断“我哭累了”。</FONT></P>
<P><FONT size=2>一句话，原来是判断“是否继续循环”，现在是判断“是否跳出循环”……</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>再来看那个“可以多次统计”的统计程序。看看是否也能把它改成使用break来结束循环。</FONT></P>
<P><FONT size=2>为了节省篇幅同时也是为了突出重点，我们将其中用于实现一次统计的代码，用一句伪代码来实现。（什么叫伪代码？我们用得很经常啊，就是那些用自然语言写的“代码”，这些代码当然无法在计算机上运行，它们只是要方便地表达实际代码要实现的功能）。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>int main(int argc, char* argv[])</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 实现统计一个学员的成绩； //伪代码，详细代码请见上章相关部分</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>　 do</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //提问是否继续统计：&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt;"是否开始新的统计？(Y/N)?";</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cin&nbsp; &gt;&gt; c;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;while( c == 'y' || c == 'Y');</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>改成用 break;</FONT></P>
<P><FONT size=2>int main(int argc, char* argv[])</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 实现统计一个学员的成绩； //伪代码，详细代码请见上章相关部分</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>　 do</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //提问是否继续统计：&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt;"是否开始新的统计？(Y/N)?";</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cin&nbsp; &gt;&gt; c;</FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; //如果用户输出的不是字母Y，说明他不想继续统计了，我们需要中断循环。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; if( c != 'y' &amp;&amp; c != 'Y')</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;}</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;while (true);</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>请首先 while(true)部分，其条件直接写上真(true),表明这是一个无条件的循环（即，循环将无条地一直持续下去），这岂不犯了程序界的武林大岂：成了一个“死循环”？其实，相信你已明白，在循环体内，有一个break的分支在呢，当判断用户输入的字母既不是小写的y，也不是大写的Y，break就起它能起的作用了。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>三个例子，都是从循环判断的条件摘出一部分或全部（最后一个例子），然后循环体中，采用一个if判断，结束break来跳出循环。可能你会问：为什么要break呢？直接用原来的方法，在while处判断条件不是很好吗？</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>break的长处在于，它可以在循环体内的任意位置进行判断。</FONT></P>
<P><FONT size=2>继续上一例。假设我们出于慎重，想在用户按入 N 时，再问他一句是否真的退出统计，则此时显示出了break的方便：</FONT></P>
<P><FONT size=2>int main(int argc, char* argv[])</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 实现统计一个学员的成绩； //伪代码，详细代码请见上章相关部分</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>　 do</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //提问是否继续统计：&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt;"是否开始新的统计？(Y/N)?";</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cin&nbsp; &gt;&gt; c;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果用户输出的不是字母Y，说明他不想继续统计了，我们需要中断循环。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( c != 'y' &amp;&amp; c != 'Y')</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //出于慎重起见，我们要再问一句用户是否真的不统计了？</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "您真的不想继续计算了？(Y:真的结束 / N:继续统计)";</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cin &gt;&gt; c;</FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这回，如果用户输入Y,表明他真的不统计了：</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( c == 'Y' || c == 'y')</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;while (true);</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>在上面例子，由于用户的两次输入我们都采用变量 c (char 类型)接收。但如果第一次输入 字母‘Y’时，循环需继续，但如果用户是在第二次输入‘Y'，则表示是真的不统计了，循环却必须结束；所以，此时while无法仅凭c的值来做出正确判断，但，采用break，正如上面代码，我们在合适的位置安排一个break，从而直观地实现了。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>当然，这里仅为了讲学方便而举此例，如果你真的在程序中为了一个“是否继续统计”而问了用户两遍，可能会被用户骂做“神经质”。不过，如果是删除某些重要数据（直接删除，不可恢复的情况），多问一次就选得很重要了。（比如句神英语删除用户操作就会在最后多问一句“真的要说再见吗？我们会想你的……”）</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>再举一例，看我们前面关于跑步的例子：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑的圈数 &lt; 3 )</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑一圈……；</FONT><FONT size=2>&nbsp; </FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp; </FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>这段代码有点问题，因为判断“我身体感觉不妙”是在跑完一圈之后……很可能我在某一圈刚开始跑时就觉得肚子剧痛，极可能是得阑尾炎啊！按照这段程序，我只有坚持跑完一圈后，才能break了……</FONT></P>
<P><FONT size=2>要完美解决这个问题，我们将在本章再后讲到，现在先采用一个“通融”的办法，我们允许你每跑100米就检查一次吧：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑完图数 &lt; 3)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑第1个100米;</FONT><FONT size=2>&nbsp; </FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp; </FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp; 跑第2个100米;</FONT><FONT size=2>&nbsp; </FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp; </FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp; 跑第3个100米;</FONT><FONT size=2>&nbsp; </FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp; </FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp; 跑第4个100米;</FONT><FONT size=2>&nbsp; </FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp; </FONT></P>
<P><FONT size=2>}</FONT></P>
<P><FONT size=2>代码中，我们将１圈拆为４个１００米，每跑完１／４，我们就检查一次是否身体不对。看明白这个例子，我想你对break的用途和用法，可以算是理解了。</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.1.2><FONT size=2>11.1.2</FONT></A><FONT size=2> break 的一个“高级用法”</FONT><FONT size=2>　</FONT></H4>
<P><FONT size=2>本小节不是很适于没有多少实际编程经历的初学者，所以初学者可以跳过,以后再回头阅读。当然，所谓的“高级用法”的确是应该加对引号的，所谈的内容只是一个高手们常用小小技巧。</FONT></P>
<P><FONT size=2></FONT></P>
<P><FONT size=2>使用do...break...while简化多级条件判断的结构。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>如果你写过不少代码，那么一定会不时遇到类似下的情况：</FONT></P>
<P><FONT size=2>假设要找到文件A，复制该文件为B；然后打开B文件，然后往B文件内写入一些内容；最后在写入成功后，我们需要再进行一些相关操作。</FONT></P>
<P><FONT size=2>在此过程，遇到以下情况时将放弃后续的操作，认为是操作失败：</FONT></P>
<P><FONT size=2>１、如果A文件不存在；</FONT></P>
<P><FONT size=2>２、如果Ｂ文件已经存在,并且询问用户是否覆盖时，用户回答“不”；</FONT></P>
<P><FONT size=2>３、无法复制出B文件；</FONT></P>
<P><FONT size=2>４、无法打开B文件；</FONT></P>
<P><FONT size=2>５、无法写入B文件；</FONT></P>
<P><FONT size=2>６、无法正常关闭B文件。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>用伪代码写该段程序为：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>if( A文件存在　)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 执行A文件的相关操作;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; if( B文件不存在 || 用户允许覆盖原有Ｂ文件）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 复制Ａ文件为Ｂ文件;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(复制文件成功）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　打开Ｂ文件；</FONT></P>
<P><FONT size=2>　　　　　　　if(打开文件成功）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 写入文件；</FONT></P>
<P><FONT size=2>　　　　　　　　　if(写入成功）</FONT></P>
<P><FONT size=2>　　　　　　　　　{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关闭Ｂ文件;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(关闭成成功）</FONT></P>
<P><FONT size=2>　　　　　　　　　　　{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行其它必须在一切成功后进行的操作。</FONT></P>
<P><FONT size=2>　　　　　　　　　　　　　……&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　&nbsp; }</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　}&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>可能有些操作和判断可以同时处理，但这个程序的繁琐仍然不可避免，而现实中程序的复杂性往往要远过于此例。从语法上看，这个例子没有任何错误，但它的一层套一层的条件判断却让人难以书写，阅读，调试，在复杂的情况就容易造成人为的错误(比如最马虎的，花括号匹配不对等……)。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>同样一段代码“程序老鸟”是这样写的：</FONT><FONT size=2>　 </FONT></P>
<P><FONT size=2>do</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(A文件不存在）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 执行A文件的相关操作;&nbsp;</FONT><FONT size=2>&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(Ｂ文件存在　&amp;&amp; 用户不允许覆盖)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT><FONT size=2>&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 复制Ａ文件为Ｂ文件;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(复制不成功)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 打开Ｂ文件；</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(打开Ｂ文件不成功)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 写入文件;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(写入文件不成功）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; 关闭Ｂ文件;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(关闭不成功）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; 执行其它必须在一切成功后进行的操作。</FONT></P>
<P><FONT size=2>　　……&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>}</FONT></P>
<P><FONT size=2>while(false);</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>看，代码是不是“直”了很多？这里用了do..while，可是根本不是为了循环，而是为了使用它的break功能。每当有操作不成功，就直接用break跳出循环。所以循环条件总是一个“永假” false。</FONT></P>
<P><FONT size=2>在一个程序中，这种结构相当的多，为了更加一步淡化while的原来的循环用途，我们非常值得在代码加入两个共用的宏：</FONT></P>
<P><FONT size=2>#define&nbsp; BEG_DOWHILE do {</FONT></P>
<P><FONT size=2>#define&nbsp; END_DOWHILE　} while(false);</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>这里举的是do...while结构，在某些情况下，可以使用while...来实现类似功能。</FONT></P>
<P><FONT size=2>　</FONT></P>
<H4><A name=11.1.3><FONT size=2>11.1.3</FONT></A><FONT size=2> break 在for循环中的一点注意</FONT></H4>
<P><FONT size=2>前面举的例子都是do...while或while，break在for循环也一个样。请看下面例题：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>例一：从１开始累加，每次递增１，请问累加到哪个数，累加和超过２０００？请输出该数，及当时的累加和。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>分析：和求１～100的累加和类似，只是在发现累加和已经超过2000时，就输出当前累加的数，然后结束循环。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>for(int i=1,sum=0;;i++)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; sum += i;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if(sum &gt; 2000)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; i &lt;&lt; "," &lt;&lt; sum &lt;&lt; endl;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>输出结果为：</FONT><FONT size=2>　</FONT></P>
<P><FONT color=#ffffff size=2><SPAN style="BACKGROUND-COLOR: rgb(0,0,0)">63，2016</SPAN></FONT></P>
<P><FONT size=2>关于这段例子，需要注意三点：1、循环条件初始的位置，我们同时声明两个变量；2、没有循环条件。为了解这两点注意，请看下面放大图：</FONT></P>
<P><FONT size=2><IMG height=244 src="http://www.d2school.com/bcyl/bhcpp/newls/images/ls11/ls11.h2.gif" width=662 border=0></FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2>最后一点注意是关于break和“条件因子变化”的注意。我们知道，for每执行一遍循环体后，都将执行一次“条件因子变化”语句（见上图③）。现在需要注意的是：</FONT></P>
<P><FONT size=2>在for循环中，执行break后，“条件因子变化”语句同样被跳过，没有被执行循环就被中断。</FONT></P>
<P><FONT size=2>（完整代码请见lz1.bpr）</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>至此，break 在 while,do...while,for中的用法我们都已见过。不过，你还记得吗，我们最早学到break是在哪里？在讲条件分支语句中switch里。如果你有点忘了那里的break是起什么作用，现在就去看看吧。</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.1.4><FONT size=2>11.1.4</FONT></A><FONT size=2> 多层循环中的break</FONT><FONT size=2>　</FONT></H4>
<P><FONT size=2>break 只能跳出当前层的循环，所以，如果有多层循环，则在内层的break跳出循环后，外层的循环还将继续。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>前面说跑步的例子，一圈400米，我们每跑100检查一下是否肚子疼什么的，如果疼得利害就break,不跑了。这和现实不符，我们应该每跑一步就检查一次是否肚子疼最合理。</FONT></P>
<P><FONT size=2>一圈得分成几步呢？显然不能再像上面分成四次检查那样写代码了。我们加一层循环，也就是把跑一圈的工作用一个循环来实现：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(一圈未结束）</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑一步；</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>然后，我们在每跑完一步时加入一个判断：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(一圈未完)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp; 跑一步;</FONT><FONT size=2>&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>把这跑一圈的代码加入外层循环：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑完图数 &lt; 3)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; while(一圈未完)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 跑一步;</FONT><FONT size=2>&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>外层的while用于负责一圈一圈循环跑完三圈，内层的while用于负责一步一步地循环跑完一圈，同时负责每跑一步就检查是否身体不妙，若身体不舒服，就跳出循环，不跑了。看起来代码很完美，其实BUG已经产生：问题就在那个break。当“我身体感觉不妙”后，程序遇上break,跳出内层while，落入外层的while,外层的循环可没有被break,所以程序将继续外层的循环。假如你跑第一圈跑了一半时肚子疼，按照这段程序逻辑，那好这第一圈剩下的一半你可以不用跑了，但后面的两圈你还得继续。</FONT></P>
<P><FONT size=2>解决的第一种方法是：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑完图数 &lt; 3)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; while(一圈未完)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 跑一步;</FONT><FONT size=2>&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;</FONT><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; if(我身体感觉不妙）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; break;&nbsp;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>我们在外层也进行了一次判断，这样当然就可保证从内层跳出来以后，外层的循环也被跳出。但在内层已经做过一次“感觉”的情况下，外层还要重新“感觉”一次，这种代码让人不爽，所以我们可以加一个变量，用于记住现在的身体状态：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>bool needBreak = false; //是否需要跳出循环</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(已跑完图数 &lt; 3)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; while(一圈未完)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 跑一步;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(我身体感觉不妙） </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; needBreak = true; //做一标志，需要break;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; } </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; if（needBreak）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; break;&nbsp;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>虽然本人的课程并不是绕什么圈子，可是在这有关break的长篇累牍的文字中，想必各位现在头脑里只有一个词，只有一个念头：break。想 break？后面的课程就不要啦？不可能，我们还是continue吧。</FONT></P>
<H3><A name=11.2><FONT size=2>11.2</FONT></A><FONT size=2> continue</FONT><FONT size=2>　</FONT></H3>
<P><FONT size=2>continue 汉意为继续。它的作用及用法和break类似。重要区别在于，当前循环遇到break，是直接结束循环，而若遇上continue,则是停步当前这一遍循环，然后直接尝试下一遍循环。我把“尝试”加粗以引起注意，为什么要注意原因后面再说，请先看下面关于break和continue的对比：</FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2><IMG height=345 src="http://www.d2school.com/bcyl/bhcpp/newls/images/ls11/ls11.h3.gif" width=443 border=0></FONT></P>
<P><FONT size=2>continue并不结束整个循环，而仅仅是中断的这一遍循环，然后跳到循环条件处，继续下一遍的循环。当然，如果跳到循环条件处，发现条件已不成立，那么循环也将结束，所以我们称为：尝试下一遍循环。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>例二：求整数1～100的累加值，但要求跳过所有个位为3的数。</FONT></P>
<P><FONT size=2>分析：在循环中加一个判断，如果是该数个位是3，就跳过该数不加。</FONT></P>
<P><FONT size=2>如何判断一个1到100中，哪些整数的个位是3呢？还是 % ，将一个2位以内的正整数，除以10以后，余数是3，就说明这个数的个位为3。</FONT></P>
<P><FONT size=2>比如： 23 ,除以10，商2，余数3。这里我们不需要商，所以用求余（也称为求模）运算：23 % 10 = 3。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>int sum = 0;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>for(int i = 1; i&lt;=100;i++)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if( i % 10 == 3)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;</FONT><FONT size=2>&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; sum += i;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>cout &lt;&lt; sum &lt;&lt; endl;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>（完整代码请见lz2.bpr）</FONT></P>
<P><FONT size=2>和break正相反：</FONT></P>
<P><FONT size=2>在for循环中，执行continue后，“条件因子变化”语句没有被跳过，将被执行一次，然后再尝试循环的下一遍。</FONT></P>
<P><FONT size=2>在上例中，当条件 i %10 ==3 成立时，continue 被执行，于是，程序首先执行 i++;然后执行 i &lt;= 100 的判断。如果将该段程序改成while，正确答案为：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>int sum = 0;</FONT></P>
<P><FONT size=2>int i = 1;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while(i &lt;= 100)</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; if( i % 10 == 3)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#000000><SPAN style="BACKGROUND-COLOR: rgb(255,255,0)"> i++;</SPAN></FONT></FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; }</FONT><FONT size=2>&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; sum += i;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; <SPAN style="BACKGROUND-COLOR: rgb(255,255,0)">i++;</SPAN></FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>cout &lt;&lt; sum &lt;&lt; endl;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>请注意程序中的两句"i++;"，缺一不可。&nbsp;</FONT><FONT size=2>　</FONT></P>
<H3><A name=11.3><FONT size=2>11.3</FONT></A><FONT size=2> goto</FONT><FONT size=2>　</FONT></H3>
<P><FONT size=2>臭名昭著的goto出场了。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>goto 的汉义为“转到”，在计算机语言里，它的完整名称为：“无条件跳转语句”。几乎所有高级语言都会劝你尽量不要使用它goto。因为它会破坏程序的模块性，严重降低一段程序的可读性。若是老外写的书，则比喻使用大量goto的代码：“像意大利面条”。嗯，其实北京的杂酱面也很缠绕……可惜没有走向世界。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>goto的用法是，首先要在代码中某处加上一个位标（也称标号），然后在代码中的需处，加上goto，并写让要跳转到位标。比如你在第三行代码加一个位标：A : ，然后可以在第10行写上一个goto A，程序执行到该行时，就将跳到第三行。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>加位标的方法是在一空行加上位标的名称，命名规则和变量一样，但最后要加上一冒号“：”。</FONT></P>
<P><FONT size=2>例如：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>int i = 1;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>A&nbsp; :</FONT><FONT size=2>&nbsp;</FONT></P>
<P><FONT size=2>cout &lt;&lt; i &lt;&lt; endl;</FONT></P>
<P><FONT size=2>i++;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>if(i &lt;= 10)</FONT></P>
<P><FONT size=2>&nbsp; goto A;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>... ...</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>goto 虽然号称“无条件跳转”，事实上倒是有些条件限制。主要是三条。</FONT></P>
<P><FONT size=2>1、goto只能在当前的同一程序段内跳转；</FONT></P>
<P><FONT size=2>2、goto 可以从循环内跳转到循环外的代码，但不能从循环外的代码跳到循环内；</FONT></P>
<P><FONT size=2>3、在有goto的跳转范围内，不能再使用C++允许的临时变量声明。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>好了，其实笔者写程序近10年，惟一用到goto的地方就是：将一段简单的程序故意用goto写得面目全非，以期能让破解程序的人因为眼晕而放弃功击……一句老话：如果没有什么特殊理由，不要在程序里使用goto。</FONT><FONT size=2>　</FONT></P>
<H3><A name=11.4><FONT size=2>11.4</FONT></A><FONT size=2>&nbsp; 流程控制强化训练</FONT><FONT size=2>　</FONT></H3>
<P><FONT size=2>这一节将提供一系列的有关流程控制的实例，程序中知识点全部不超过你学到本章时的水平。有些程序需要一些数学上的小小技巧。</FONT></P>
<P><FONT size=2>所有实例是从建立一个新的控制台工程开始。所以一些由ＣＢ自动生成代码我将不写出。你应该知道如何将它们写成一个完整的控制台程序。如果实在有困难也不要紧，各个实例的完整我都已经提供下载。（但只有付费报名学员可以通过课程下载器下载，解密）。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>最后，在例子中会出现不少常见的编程技巧，可能在前面的课程中没有直接讲到，我会对这些技巧进行解说。</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.4.1><FONT size=2>11.4.1</FONT></A><FONT size=2> 求绝对值</FONT></H4>
<P><FONT size=2>例三：用户输入一整数，请用程序输出绝对值</FONT></P>
<P><FONT size=2>分析：</FONT></P>
<P><FONT size=2>1、本例演示了一个最简单的流程控制：if...</FONT></P>
<P><FONT size=2>2、同时你可以学到如何求一个数的绝对值，很简单;另外，看一个数是否为负数，就是看它是否小于0，这也很简单。</FONT></P>
<P><FONT size=2>3、另外，本例使用一个 while(true)来无限循环，你可以不断地输入，如果要中止程序，请按Ctrl+C,这是由操作系统提供的，DOS窗口下中止程序的热键。(因此，本例也无须在最后加 getchar();这行代码)</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>答案: </FONT></P>
<P><FONT size=2>#include &lt;iostream.h&gt;<BR>　</FONT></P>
<P><SPAN lang=EN-US><FONT size=2>int main(int argc, char* argv[])</FONT></SPAN></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; int num;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; while（true）</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "求绝对值的程序" &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "要中止运行请按 Ctrl + C " &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "==============" &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "请输入一个整数：";</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cin&nbsp; &gt;&gt;&nbsp; num;</FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //正数和0的绝对值是本身，负数的绝对值为其相反数</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(num &lt; 0)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num = -num;</FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "绝对值为：" &lt;&lt; num &lt;&lt; endl &lt;&lt; endl;&nbsp; //输出两个换行，仅是为了美观</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.4.2><FONT size=2>11.4.2</FONT></A><FONT size=2> 判断用户输入字符的类型</FONT><FONT size=2>　</FONT></H4>
<P><FONT size=2>例四：用户输入一字符，请判断该字符是：大写字母，小写字母，数字字符，其它字符。</FONT></P>
<P><FONT size=2>分析：</FONT></P>
<P><FONT size=2>1、本题主要演示多级 if..else...</FONT></P>
<P><FONT size=2>2、在ASCII表中，题中所提的 前3类字符，其ASSCII值都各自连续（换句话说就是：所有的大写字母都是连续的，所有在小写字母也是连续的……）。基于这一点，你容易看明白代码中为判断字符类型的方法。</FONT></P>
<P><FONT size=2>3、本解答也采用了循环，所以也不用加getchar()这行代码。关于循环中条件判断方法比较特殊，请见代码后的说明。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>#include &lt;iostream.h&gt;</FONT></P>
<P><FONT size=2>#include &lt;conio.h&gt;</FONT><FONT size=2>　</FONT><SPAN lang=EN-US><FONT size=2> </FONT></P>
<P><FONT size=2>int main(int argc, char* argv[])</FONT></P></SPAN>
<P><FONT size=2></FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; char ch;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; cout &lt;&lt; "请输入一个字符：" &lt;&lt; endl;</FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; while( (ch = getche()) != '\r' )</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl; //加一个换行，仅为了输出美观</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ch &gt;= 'A' &amp;&amp; ch &lt;= 'Z')</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; ch &lt;&lt; "是一个大写字母。" &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if ( ch &gt;= 'a' &amp;&amp; ch &lt;= 'z')</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; ch &lt;&lt; "是一个小写字母。" &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if( ch &gt;= '0' &amp;&amp; ch &lt;= '9')</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; ch &lt;&lt; "是一个数字字符。"&nbsp; &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; ch &lt;&lt; "是一个其它的字符。" &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=2>｝</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>这段代码中，我们用到了getche()库函数，它的声明包含在　conio.h　文件中，所以本例程除了"#include &lt;iostream.h&gt;"以外，还另需 "#include &lt;conio.h&gt;"。</FONT></P>
<P><FONT size=2>getche() 和我们常用的 getchar()同样是接收用户从键盘输入的一个字符，但getchar()在用户输入字符后，用户还需要敲一下回车键才能完成输入；而getche()则在用户敲入一个字符后，立即完成。本例中，我们希望如果用户敲一个回车键，则程序自动结束（见下面解析），所以我们采用getche()函数。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>现在来看while的循环条件：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>while( (ch = getche()) != '\r' )</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>这行代码依次完成下面两件事：　</FONT></P>
<P><FONT size=2>首先是： ch = getche() ，它等待用户敲入一字符，然后将该字符存储在ch变量。</FONT></P>
<P><FONT size=2>然后是判断条件：　（……） != '\r' 。 程序判断 ch 是否不等于　'\r', '\r' 即回车(return)字符。也就是看用户输入的字符是否为回车键，如果不是，则循环继续，如果是，则循环结束。</FONT></P>
<P><FONT size=2>记住，在Ｃ和Ｃ＋＋里　一个赋值表达式：　A = B,　本身也有值，值就是完成赋值后的Ａ。在上例中，A是ch,B是 getche()。在Ｃ，Ｃ＋＋里，几乎所有表达式本身都有值，比如：１＋２　的值是３；而表达式 a = 3　的值为３。</FONT></P>
<P><FONT size=2>理解这段代码，最好的方式就是在ＣＢ中运行它。至于我们所要练习的多级if...else在例中的表现，我不再多说，你需要自已看懂它。</FONT></P>
<P><FONT size=2>最后解释一下　conio.h,　其中 con 即我们总说的控制台，io则和iostream中的io一样，指：input/output。</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.4.3><FONT size=2>11.4.3</FONT></A><FONT size=2>　等腰三角形图形的输出</FONT></H4>
<P><FONT size=2>例五：请输出以下图形：</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp; *** </FONT></P>
<P><FONT size=2>　&nbsp; ***** </FONT></P>
<P><FONT size=2>&nbsp;&nbsp; ******* </FONT></P>
<P><FONT size=2>&nbsp; ********* </FONT></P>
<P><FONT size=2>分析： </FONT></P>
<P><FONT size=2>新手刚看这道词可能觉得无从下手，其实，如果把图形改成一个矩形： </FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp; ********* </FONT></P>
<P><FONT size=2>&nbsp; *********</FONT></P>
<P><FONT size=2>&nbsp; *********</FONT></P>
<P><FONT size=2>&nbsp; *********</FONT></P>
<P><FONT size=2>&nbsp; *********</FONT></P>
<P><FONT size=2>那么就很好解决了：输出５行，其中每行都输出９个*　。</FONT><FONT size=2>　 </FONT></P>
<P><FONT size=2>for(int i=0;i&lt;5;i++) </FONT></P>
<P><FONT size=2>{ </FONT></P>
<P><FONT size=2>&nbsp; for(int j=0;j&lt;9;j++) </FONT></P>
<P><FONT size=2>&nbsp; { </FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; cout &lt;&lt; '*'; </FONT></P>
<P><FONT size=2>&nbsp; } </FONT></P>
<P><FONT size=2>} </FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>对于三角形，程序仍然是这个结构：需要两层循环。同样是要输出５行，所以外层循环不变；不同的地方在于每一行输出的内容。其实三角形同样是输出一个矩形，只不过有些地方要打空格，有些地方要打*，以下我们用“-”表示空格，则三角形实为：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp; ----*----</FONT></P>
<P><FONT size=2>&nbsp; ---***---</FONT></P>
<P><FONT size=2>　--*****-- </FONT></P>
<P><FONT size=2>&nbsp; -*******- </FONT></P>
<P><FONT size=2>&nbsp; *********</FONT></P>
<P><FONT size=2>所以，问题的重点在于：在每一行中，哪些地方要输出空格，哪些地方要输出星号？如果我们行和列都从１开始编号，如图：</FONT></P>
<P><FONT size=2><IMG height=237 src="http://www.d2school.com/bcyl/bhcpp/newls/images/ls11/ls11.h1.gif" width=240 border=0></FONT></P>
<P><FONT size=2>仔细观察我们发现，哪一列要打星，哪一列要打空格，主要和该列与第５列（红线所在列）的距离有关：</FONT></P>
<P><FONT size=2>第　１　行：　只有第５列本身打星，第５列和第５列（自身）的距离是０</FONT></P>
<P><FONT size=2>第　２　行：　除了第５列以外，增加第４、６列，４和６与５的距离都为１</FONT></P>
<P><FONT size=2>第　３　行：　增加了３、７两列要打星，３，７两列和５的距离都为２</FONT></P>
<P><FONT size=2>……</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>行了，规律就是：在第ｎ行内，凡是和第５列的距离小于ｎ的列，都要打星，其余的列打空格。</FONT></P>
<P><FONT size=2>下面代码中，row表示当前行，col表示当前列。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>答案：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>#include &lt;iostream.h&gt;</FONT></P>
<P><FONT size=2>int main(int argc, char* argv[])</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; for(int row=1;row&lt;=5;row++)</FONT></P>
<P><FONT size=2>&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int col=1;col&lt;=9;col++)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( col-5 &gt; -row &amp;&amp; col-5 &lt; row)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "*";<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;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; " ";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl;<BR>&nbsp;&nbsp; }<BR><BR>&nbsp; getchar();<BR><BR>&nbsp; return 0;<BR>&nbsp; }<BR></FONT></P>
<P><FONT size=2>以下是输出结果：</FONT></P>
<P><FONT size=2><IMG height=83 src="http://www.d2school.com/bcyl/bhcpp/newls/images/ls11/ls11.h4.gif" width=89 border=0></FONT></P>
<P><FONT size=2>在本例中，为了保持大家日常生活的习惯，我对行，列的编号均从１开始，其实，Ｃ，Ｃ＋＋程序员更习惯于编程从０开始，即原来的第１行现在称为第０行，第１列称为第０列，则相关代码如下(黑体部分为改动处)：</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;for(int row=0;row&lt;5;row++)</FONT></P>
<P><FONT size=2>&nbsp; {</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int col=0;col&lt;9;col++)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( col-4 &gt;= -row &amp;&amp; col-4 &lt;= row)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "*";<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;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; " ";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl;<BR>&nbsp;&nbsp; }<BR></FONT></P>
<P><FONT size=2>学会从０开始索引的思想方法，这也是大家所要注意的，否则在阅读别人代码时会比较困难。</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.4.4><FONT size=2>11.4.4</FONT></A><FONT size=2> 输出正弦曲线图</FONT><FONT size=2>　</FONT></H4>
<P><FONT size=2>例六：请在ＤＯＳ窗口输出正弦曲线图</FONT></P>
<P><FONT size=2>分析：</FONT></P>
<P><FONT size=2>１、还记得初中代数学的正弦函数吧？</FONT></P>
<P><FONT size=2>　　y = sin (x);</FONT></P>
<P><FONT size=2>　　当ｘ从０到２<SPAN style="FONT-SIZE: 10.5pt">π变化时，ｙ的值在 -1 和 +1 之间变化。</SPAN></FONT></P>
<P><SPAN style="FONT-SIZE: 10.5pt"><FONT size=2>　　我们现在的任务就是随着ｘ（位置）的变化，在ｙ的位置上打一个点即可。</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 10.5pt"><FONT size=2>２、Ｃ为我们提供了sin的库函数。只要我们给它ｘ的值，它就能计算出相应的ｙ值。sin(x)函数包含在头文件main.h里。</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 10.5pt"><FONT size=2>３、为了方便，我们将“竖”着输出曲线，即ｘ的值由上而下增长，而ｙ值则在左右“摇摆”。并且，如果ｙ值为负数的话，那么将输出到屏幕的最左边外面，所以我们将ｙ值统一加上一值，用于向右偏到合适的位置。至于要加多大的值，和第４点有关。</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 10.5pt"><FONT size=2>４、和前面输出“等腰三角形”类似。假如我们需要在屏幕的某一行最右边（行末）打出一个点，我们的方法是在前边连续地打满空格。正弦值在 -1到１之间，我们不可能打零点几个空格，所以，需要正弦值放大一定的倍数。</FONT></SPAN><FONT size=2>　</FONT></P>
<P><SPAN style="FONT-SIZE: 10.5pt"><FONT size=2>答案：</FONT></SPAN></P>
<P><FONT size=2>int main(int argc, char* argv[])</FONT></P>
<P><FONT size=2>{</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; #define PI 3.14159</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; int scale = 30; //放大倍数</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; double X,Y;</FONT></P>
<P><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; for(float X = 0.0; X &lt;= 2 * PI; X += 0.1)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; {</FONT></P>
<P><FONT size=2>　　　 // 乘上scale 是为了放大Ｙ值，而加上scale则是为了向右边偏移</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 以保证所有的点都不会跑出屏幕左边。</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y = sin(X) * scale + scale;&nbsp;&nbsp;</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //前面打空格</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int dx = 0;dx&lt;Y;dx++)</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; ' ';</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; '.' &lt;&lt; endl;</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp; }</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; getchar();</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>&nbsp;&nbsp; return 0;</FONT></P>
<P><FONT size=2>}</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>完整的代码请查代码文件。由于输出画面太长，所以这里不显示结果图。</FONT><FONT size=2>　</FONT></P>
<H4><A name=11.4.5><FONT size=2>11.4.5</FONT></A><FONT size=2> 标准体重计算程序</FONT><FONT size=2>　</FONT></H4>
<P><FONT size=2>尽管类似输出“九九口诀表”、“等腰三角形”，“正弦曲线”这些题目对锻练大家的编程思维颇为有益，但可能很多人都不会喜欢这种题。</FONT></P>
<P><FONT size=2>嗯，这很多人当中，就有我自已一个。所以，我们来点有趣的题目吧。 </FONT></P>
<P><FONT size=2>街上有一种电子称，你站上去一量身高体重，它就会告诉你的身材是否为标准体重。可是有一天我兴冲冲地往上一站，那机器竟怪里怪气地说：“本仪器不适于非洲儿童……”。害得我当众狼狈而逃！</FONT></P>
<P><FONT size=2>回去后，我痛下血本，每天大鱼大肉，如此月余，自认为横了一点，很想再测测这回该是哪一洲的儿童。然而由于上次的经历已经对我的造成了极大的心灵伤害，以致于我上街看见那种电子称就腿软。只好自购小站秤一台，米尺一条，不过，如何计算是否标准体重呢？嗯，就是这节课的“标准体重计算程序”了。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>计算标准（理想）体重的方法是从网上搜到的：</FONT><FONT size=2>　</FONT></P>
<P><FONT face=楷体_GB2312 size=2>“最近军事科学院还推出一种计算中国人理想体重的方法：</FONT></P>
<P><FONT face=楷体_GB2312 size=2>北方人理想体重＝〔身高cm—150〕x0．6十50(kg)</FONT></P>
<P><FONT face=楷体_GB2312 size=2>南方人理想体重＝〔身高cm—150〕x0．6十48(kg)”</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>（原文请见：</FONT><A href="http://www.999.com.cn/Special/disease/fat/200012/5278820001226.htm" target=_blank><FONT size=2>三九健康网</FONT></A><FONT size=2>）</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>考虑到女性一般要比男性轻，所以如果是女性，我们还需要将标准体重减去２公斤。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>可见，要计算一个人的标准体重，必须知道是男人女人，是北方人还是南方人,及他的身高。</FONT></P>
<P><FONT size=2>用户还必须输入他的现实体重，这样，在程序计算出标准体重之后，我们计算实际体重在标准体重百分之几的范围之内，作出不同判断。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>代码请见例程文件，加有详细的注解。本题事实上没有什么复杂算法，所以比前面的题都要简单－－尽管代码看上去长多了。</FONT></P>
<P><FONT size=2>试用时请注意: 程序需要输入数字时，如果不小心输入字母并回车，将引起死循环，这是cin的问题所致，请按Ctrl + C　强行退出即可。</FONT><FONT size=2>　</FONT></P>
<P><FONT size=2>在课程的最后，测一下自已的体重与“理想体重”的差距，是个不错的选择……测好了？能告诉我程序对你的身材所作的评价吗？</FONT></P></DIV>
<P>读罢文章，感触很深……</P>
<P>原来还自以为 C 语言学得很得意，谁想到头来连一个小小的 break 有这么多有价值的用法都不知道，惭愧啊……其实我要学的其实还有很多，学无止境啊！</P>]]></description>
</item><item>
<title><![CDATA[【转】如何编写网络监视器]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=12498</link>
<author>binaryluo</author>
<pubDate>2006/3/13 16:32:09</pubDate>
<description><![CDATA[<A><FONT size=2>　</FONT></A><A><FONT size=2>　</FONT></A><FONT size=2> </FONT>
<P><FONT size=2>今天终于找到一篇好文章。立刻把它转下来。</FONT></P>
<P><FONT size=2>原文出处：</FONT><A href="http://www.driverdevelop.com/article/znsoft_ndis-sniffer.mht#xx907xx"><FONT size=2>http://www.driverdevelop.com/article/znsoft_ndis-sniffer.mht#xx907xx</FONT></A></P>
<P><FONT size=2>发布者：soarlove</FONT></P>
<P><FONT size=2>本文简单地介绍了NDIS (Network Driver Interface Specification 即网络驱动接口规范)，以及应用程序如何与一个驱动程序交互，如何最好地利用驱动程序。作为例子，本文提供了一个应用程序使用Packet.sys的网络协议层驱动程序的例子，读者在这个例子的基础上可以实现象Netxray等局域网数据包截获程序的功能。 <BR>　　Packet.sys是DDK中的一个非常有用的驱动程序，通过它你能够接收以太网中所有经过你的电脑的数据包，并且可以脱离系统的TCP/IP协议栈独立发送数据包，即通过Packet.sys建立的与TCP/IP同层次的协议发送数据包。<BR><BR>基础知识介绍<BR><BR>1. 驱动程序 Driver<BR>设备驱动程序是拥有与Windows内核相同的最高特权的程序，它是在操作系统与输入/输出设备之间的一层必不可少的"胶水"。它的作用相当于转换器，将从操作系统发来的原始的请求转换成某种外围设备能够理解的命令。<BR>系统程序员的主要工作就是编写驱动程序，与系统的底层打交道。许多在应用程序中称为"mission impossible"即不可能完成的任务在使用了驱动程序后就可以轻易解决。编写驱动程序最主要的目的当然是为了驱动真正的硬件，使系统能够顺利地控制各种不同型号的外围设备或内部硬件，称为硬件驱动程序，象显卡驱动程序、网卡驱动程序、PCI总线驱动程序等等；还有的驱动程序是为了实现一些应用程序不能够完成的功能的，有的虽然在逻辑上实现了一个硬件的功能，但是物理上并不存在这个硬件，象虚拟光驱，这一大类则称为软件驱动程序，象TCP/IP驱动程序、防火墙的驱动程序、虚拟光驱的驱动程序等等。<BR>在Windows 9x/Me中支持Vxd驱动程序和WDM(Windows Driver Model)驱动程序，Windows NT中支持Kernel Driver即内核式驱动程序，Windows 2000及以后版本的Windows使用WDM驱动程序。Windows NT的内核式驱动程序与WDM驱动程序很相似，只是少了部分功能，而Vxd式驱动程序行将淘汰，所以我们这里用的是WDM驱动程序。<BR><BR>2. 网络接口卡 Network Interface Card (NIC)<BR>网络接口卡俗称网卡，它是一种硬件设备，作用是在电脑的内部总线和网络的传输介质中充当大门的作用，通过它，我们可以向网络上发送和接收数据包。一般网卡的名称随着它所在网络的类型不同而不同，象处于以太网中的网卡叫做以太网卡，处于令牌网中的网卡叫做令牌网卡。我们这篇文章中讲的是在以太网中的应用。<BR><BR>3. 网络驱动接口规范 Network Driver Interface Specification（NDIS）<BR>　　随着计算机网络蓬勃发展，网络相关的驱动程序成为驱动中的热点。为了提高编写网络驱动程序的效率，也为了使各种协议驱动在各种网卡之间独立，Microsoft创建了一个网络驱动程序界面规范，即Network Device Interface Specification (NDIS)，这个规范是为原本复杂的网络驱动程序编写框架提供一个并不严格的封装，在这个规范下，编写网络驱动程序中原来应该使用系统有关函数都变换为通过NDIS.sys这个接口，而内部实现的细节由NDIS.sys实现，这样，不仅提高了编写效率，程序员不易出错，而且也增强了驱动程序的强壮性、可维护性，设备独立性等性能。<BR>　　目前最新的NDIS是5.1版本，Windows 2K及以后版本的NDIS是5.0，我的例子中使用的是Windows 2K DDK。<BR>NDIS程序库(NDIS.sys)提供了一个面向NIC驱动程序的完全抽象的接口，如下图所示，网卡驱动程序与协议层驱动程序及操作系统通过这个接口进行通信。我们可以把这个接口看做Microsoft为网络驱动设计者提供了一个设计网络驱动程序所必须的抽象的伪"类"。（我个人认为，Microsoft引入NDIS是一个在C++的面向对象和C的高编译效率之间的一个折衷，就象MFC封装了WinAPI一样，以后Microsoft迟早会推出真正面向对象标准的DDK，就像现在DriverStudio等某些驱动编写工具所做的那样）NDIS库输出了所有的能够在NIC驱动开发中使用的NT内核模式函数。NDIS库还参与管理操作系统中的与网络有关的特定任务，管理所有底层的NIC驱动的绑定与状态信息。<BR><BR><BR><BR>NDIS驱动程序有三种类型，分别是网络接口卡驱动程序、中间层驱动程序、高层协议驱动程序。<BR><BR>A. 网络接口卡驱动程序 Miniport Network Interface Card drivers<BR><BR>网络接口卡驱动程序管理网络接口卡，NIC驱动程序在它的下端直接控制网络接口卡硬件，在它的上端提供一个较高层的驱动能够使用的接口，这个接口一般完成以下的一些任务：初始化网卡，停止网卡，发送和接收数据包，设置网卡的操作参数等等。<BR>NIC驱动程序分为以下两种：<BR><BR>l 无连接的微端口驱动程序 (Connectionless Miniport Drivers)<BR>无连接的微端口驱动程序是控制无连接的网络介质上的网卡的驱动程序，象以太网(Ethernet)、光纤分布式数据接口(FDDI)、令牌网(Token Ring)。<BR><BR>l 面向连接的微端口驱动程序 (Connection-oriented Miniport Drivers)<BR>面向连接的微端口驱动程序是控制面向连接的网络介质上的网卡的驱动程序，象异步传输模式（ATM）。<BR><BR>B. 中间层驱动程序 Intermediate Protocol Driver<BR><BR>中间层驱动程序在协议驱动程序和微端口驱动程序之间。在高层的传输层驱动程序看来，中间层驱动程序象一个微端口驱动程序，而在底层的微端口驱动程序看来，它象一个协议驱动程序。使用中间层驱动程序的最主要的原因可能是在一个已经存在的传输层驱动程序和一个使用新的，传输层驱动程序并不认识的媒体格式的微端口驱动程序中相互转换格式，即充当翻译的角色。<BR><BR>C. 高层的协议驱动程序 Upper Level Protocol Driver<BR><BR>　　象各种TCP/IP协议，一个协议驱动程序完成TDI接口或者其他的应用程序可以识别的接口来为它的用户提供服务。这些驱动程序分配数据包，将用户发来的数据拷贝到数据包中，然后通过NDIS将数据包发送到低层的驱动程序，这个低层的驱动程序可能是中间层驱动程序，也可能是微端口驱动程序。当然，它在自己的下端也提供一个协议层接口，用来与低层驱动程序交互，其中最主要的功能就是接收由低层传来的数据包，这些通讯基本上都是由NDIS完成的。<BR><BR>4. 驱动程序与应用程序的交互<BR>在windows NT/2K下编写的驱动程序都必须要包括一个名叫DriverEntry入口函数，这个函数是作为系统载入驱动程序时的入口点，它主要进行一些初始化及告诉系统各个回调函数的位置，系统只有通过DriverEntry函数才能够知道驱动程序中其他的函数。应用层的调用象CreateFile,ReadFile等等将导致NT输入/输出管理器生成一个与应用层的调用相对应的IRP(Input/Output Request Packet 输入/输出请求包)。在Windows NT下，几乎所有的输入/输出操作都是包驱动的，也就是每个I/O操作都是输出输入管理器向各个相关驱动程序发送IRP来实现的。IRP是一个数据结构，里面包含了完成这个I/O操作需要的各个参数和最终的状态等返回值。<BR><BR>网络监视器例子原理<BR><BR>　　好，基础知识都介绍完毕，下面我将讲解一个非常有用的例子，要应用这个例子，必须要有微软的驱动程序开发包，即DDK，我们使用的是开发包里的一个例子：协议层驱动程序Packet.sys，今天我们只解决如何在应用层使用这个驱动程序，以后再讲解Packet.sys的细节。Packet.sys是一个协议层驱动程序，它工作在OSI中的传输层，见下图，也就是说，<BR><BR><BR>　　如果你将它加载到系统中的话，你就拥有一个与TCP/IP、IPX等等协议层驱动程序同等级的协议层，这是一个令人兴奋的事情，至少我当初是这么想的：你可以脱离TCP/IP而自己发送接收数据包，你可以完成许多原来不能完成的事情，象截获局域网(我讲的是以太网，由于以太网的广播性质，所以网上的所有机器都可以获得网上数据包的复本)上的经过你的机器这个网络结点的所有的数据包，这个功能就是Netxray等网络监视软件的基本原理，如果你想做局域网访问限制器的话，只有根据接收的数据包稍加修改再发送出去就可以了。所以说，这个驱动的应用范围是非常广的，当然也是非常有用的。<BR><BR>　　下面讲讲网卡的工作过程，下面所说的都是在一个局域网里的情况：当一个机器向网上发送出一个数据包的时候，网上的所有机器上的网卡都将接收到这个数据包，它将判断这个数据包的目的地是不是它，如果是的话就接纳，如果不是就丢弃。<BR>网卡有几个工作模式：广播模式、多播模式、直接模式和混杂模式。<BR>　　网卡在设置为广播模式时，它将会接收所有目的地址为广播地址的数据包，一般所有的网卡都会设置为这个模式。<BR>　　网卡在设置为多播模式时，当数据包的目的地址为多播地址，而且网卡地址是属于那个多播地址所代表的多播组时，网卡将接纳此数据包，即使一个网卡并不是一个多播组的成员，程序也可以将网卡设置为多播模式而接收那些多播的数据包。<BR>　　网卡在设置为直接模式时，只有当数据包的目的地址为网卡自己的地址时，网卡才接收它。<BR>　　网卡在设置为混杂模式时，它将接收所有经过的数据包，这个特性是我们要编写网络监视程序的关键。<BR><BR>　　当然一般的应用程序是不能轻易设置网卡的工作模式的，不过我们借助Packet.sys驱动程序就可以将网卡设置为以上的任意模式。在我们的例子中，我们将网卡设置为混杂模式以接收所有的数据包。<BR>　　Packet.sys是NT DDK中的一个例子。这个驱动程序能够把网卡设置为我们需要的任意模式，允许应用程序通过它向网上发送和接收数据包。这个例子中还包括了一个方便使用驱动程序的DLL，Packete32.dll，它提供给应用程序一个方便的接口，而与驱动程序通讯相关的复杂的内部操作由DLL完成，面向应用层的程序员不需要了解这些细节。下面的图形描述了我们的程序是如何同网卡通信的。应用程序调用了Packet32.dll中的函数，函数接着调<BR><BR><BR>　　用了Packet.sys中与请求相对应的入口点，驱动程序使用了Ndis.sys中输出的函数来与网卡通信。<BR>在上面的过程中使用了以下的数据结构：<BR><BR>typedef struct _ADAPTER<BR>{<BR>HANDLE hFile; // 包含由CreateFile 函数返回的句柄<BR>TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; <BR>// 驱动程序的符号链接SymbolicLink<BR>} ADAPTER, *LPADAPTER;<BR><BR>typedef struct _PACKET<BR>{<BR>HANDLE hEvent; // 一个用于Adapter对象的事件的句柄<BR>OVERLAPPED OverLapped; // 用于与驱动程序异步输入输出的Overlapped结构<BR>PVOID Buffer; // 发送或接收的数据包的缓冲区首指针<BR>UINT Length; // Buffer的实际长度<BR>} PACKET, *LPPACKET;<BR><BR>typedef struct _CONTROL_BLOCK<BR>{<BR>LPADAPTER hFile; // 网卡对象的指针<BR>HANDLE hEvent; // event 的句柄<BR>TCHAR AdapterName[64]; // 网卡的名称<BR>// 接收的数据包的缓冲区<BR>HANDLE hMem; <BR>LPBYTE lpMem;<BR>// 发送的数据包的缓冲区<BR>HGLOBAL hMem2;<BR>LPBYTE lpMem2;<BR>ULONG PacketLength; // 数据包的长度<BR>ULONG LastReadSize; // 最后一次读取的长度<BR>UINT BufferSize; // 缓冲区的长度<BR>} CONTROL_BLOCK, *PCONTROL_BLOCK;<BR><BR>下面是在应用程序中调用DLL的关键代码。<BR><BR>// 变量定义<BR>CONTROL_BLOCK cbAdapter;<BR>// 从注册表中得到网卡的名称<BR>ULONG NameLength=64;<BR>PacketGetAdapterNames(<BR>CbAdapter.AdapterName,<BR>&amp;NameLength<BR>);<BR>CbAdapter.BufferSize=1514; // 以太网帧的最大长度<BR><BR>// 分配并锁定内存用来作为发送或接受缓冲区<BR>CbAdapter.hMem=GlobalAlloc(GPTR, 1514);<BR>CbAdapter.lpMem=(LPBYTE)GlobalLock(CbAdapter.hMem);<BR>CbAdapter.hMem2=GlobalAlloc(GPTR,1514);<BR>CbAdapter.lpMem2=(LPBYTE)GlobalLock(CbAdapter.hMem2);<BR>// 打开网卡以接收发送数据包，这些代码调用DLL中的PacketOpenAdapter函数，这个<BR>// 函数调用CreateFile函数，这样就打开了网卡与我们的协议驱动程序的绑定，使我们<BR>// 可以在以后进行读写操作<BR>CbAdapter.hFile=(ADAPTER*)PacketOpenAdapter(CbAdapter.AdapterName);<BR>// OpenAdapter失败<BR>if (CbAdapter.hFile = = NULL)<BR>{<BR>AfxMessageBox("Open Adapter failed");<BR>}<BR>// 一个接收PacketAllocatePacket函数返回值的void 指针<BR>PVOID Packet;<BR>// 将网卡的工作模式设置为混杂模式<BR>Filter=NDIS_PACKET_TYPE_PROMISCUOUS;<BR>PacketSetFilter(<BR>CbAdapter.hFile,<BR>Filter<BR>);<BR>// 分配缓冲区用来接收数据包<BR>Packet=PacketAllocatePacket(CbAdapter.hFile);<BR>// 初始化接收缓冲区<BR>// 这些代码调用DLL中的PacketInitPacket来初始化Packet对象，这个Packet对象是用<BR>// 来保存接收网上的数据包<BR>if(Packet != NULL)<BR>{<BR>PacketInitPacket(<BR>(PACKET *)Packet,<BR>(char *)pdData[nCurrentWriteLocation].pData,<BR>1514<BR>);<BR>// 从网卡驱动程序中读取数据包<BR>PacketReceivePacket(<BR>CbAdapter.hFile,<BR>(PACKET *)Packet,<BR>TRUE,<BR>&amp;pdData[nCurrentWriteLocation].nPacketLength<BR>);<BR>}<BR><BR>以上代码清楚地描述了应用程序如何使用Packet.sys驱动程序将网卡设置为混杂模式，这样我们就可以接收到经过我们电脑的所有数据包了。<BR><BR>下面是一些我们在应用程序中主要用到的Packet32.dll中的函数。<BR><BR>l PacketGetAdapterNames<BR>PacketGetAdapterNames函数从注册表中获得每个网卡的名称。<BR><BR>ULONG<BR>PacketGetAdapterNames(<BR>PTSTR pStr,<BR>PULONG BufferSize<BR>)<BR>{<BR>HKEY SystemKey;<BR>HKEY ControlSetKey;<BR>HKEY ServicesKey;<BR>HKEY NdisPerfKey;<BR>HKEY LinkageKey;<BR>LONG Status;<BR>DWORD RegType;<BR><BR>// 依次打开键，并读取键值<BR>Status=RegOpenKeyEx(<BR>HKEY_LOCAL_MACHINE,<BR>TEXT("SYSTEM"),<BR>0,<BR>KEY_READ,<BR>&amp;SystemKey<BR>);<BR>if (Status == ERROR_SUCCESS) {<BR>Status=RegOpenKeyEx(<BR>SystemKey,<BR>TEXT("CurrentControlSet"),<BR>0,<BR>KEY_READ,<BR>&amp;ControlSetKey<BR>);<BR>if (Status == ERROR_SUCCESS) {<BR>Status=RegOpenKeyEx(<BR>ControlSetKey,<BR>TEXT("Services"),<BR>0,<BR>KEY_READ,<BR>&amp;ServicesKey<BR>);<BR>if (Status == ERROR_SUCCESS) {<BR>Status=RegOpenKeyEx(<BR>ServicesKey,<BR>TEXT("Packet"),<BR>0,<BR>KEY_READ,<BR>&amp;NdisPerfKey<BR>);<BR>if (Status == ERROR_SUCCESS) {<BR>Status=RegOpenKeyEx(<BR>NdisPerfKey,<BR>TEXT("Linkage"),<BR>0,<BR>KEY_READ,<BR>&amp;LinkageKey<BR>);<BR>if (Status == ERROR_SUCCESS) {<BR>Status=RegQueryValueEx(<BR>LinkageKey,<BR>TEXT("Export"),<BR>NULL,<BR>&amp;RegType,<BR>(LPBYTE)pStr,<BR>BufferSize<BR>);<BR>// 关闭上面所有打开的键<BR>RegCloseKey(LinkageKey);<BR>}<BR>RegCloseKey(NdisPerfKey);<BR>}<BR>RegCloseKey(ServicesKey);<BR>}<BR>RegCloseKey(ControlSetKey);<BR>}<BR>RegCloseKey(SystemKey);<BR>}<BR>return Status;<BR>}<BR><BR>l PacketOpenAdapter<BR>下面的PacketOpenAdapter函数的流程：<BR><BR>　　上面的流程是从应用程序的PacketOpenAdapter函数调用开始的，这也适用于所有其他的函数调用。函数PacketOpenAdapter为设备(Device)定义了一个新的DOS设备名(DOS Device Name，通过这个DOS设备名，我们应用层的程序才可以向驱动程序提出请求)，接着调用CreateFile函数来建立并打开一个联系设备的文件句柄。这个函数必须在我们进行其他操作比如读写数据包之前完成。CreateFile函数将进入驱动程序的IRP_MJ_CREATE入口点，在这里，它调用了NDIS库中输出的函数NdisOpenAdapter来完成操作。<BR><BR>PVOID<BR>PacketOpenAdapter(<BR>LPTSTR AdapterName<BR>)<BR>{<BR>LPADAPTER lpAdapter;<BR>BOOLEAN Result;<BR><BR>ODS("Packet32: PacketOpenAdapter\n");<BR>// 为Adapter 对象分配全局内存<BR>lpAdapter=(LPADAPTER)GlobalAllocPtr(<BR>GMEM_MOVEABLE | GMEM_ZEROINIT,<BR>sizeof(ADAPTER)<BR>);<BR>if (lpAdapter==NULL) {<BR>ODS("Packet32: PacketOpenAdapter GlobalAlloc Failed\n");<BR>return NULL;<BR>}<BR>// 将名称拷贝到Symbolic link中<BR>wsprintf(<BR>lpAdapter-&gt;SymbolicLink,<BR>TEXT("\\\\.\\%s%s"),<BR>DOSNAMEPREFIX,<BR>&amp;AdapterName[8]<BR>);<BR>// 为设备定义一个DOS设备名<BR>Result=DefineDosDevice(<BR>DDD_RAW_TARGET_PATH,<BR>&amp;lpAdapter-&gt;SymbolicLink[4],<BR>AdapterName<BR>);<BR>if (Result)<BR>{<BR>// 创建一个设备的文件句柄（file handle）<BR>lpAdapter-&gt;hFile=CreateFile(lpAdapter-&gt;SymbolicLink,<BR>GENERIC_WRITE | GENERIC_READ,<BR>0,<BR>NULL,<BR>CREATE_ALWAYS,<BR>FILE_FLAG_OVERLAPPED,<BR>0<BR>);<BR>if (lpAdapter-&gt;hFile != INVALID_HANDLE_VALUE) {<BR>return lpAdapter;<BR>}<BR>}<BR>ODS("Packet32: PacketOpenAdapter Could not open adapter \n");<BR>GlobalFreePtr(<BR>lpAdapter<BR>);<BR>return NULL;<BR>}<BR><BR>l PacketAllocatePacket<BR>下面的函数PacketAllocatePacket为packet对象分配内存。<BR><BR>PVOID<BR>PacketAllocatePacket(<BR>LPADAPTER AdapterObject<BR>)<BR>{<BR>LPPACKET lpPacket;<BR>// 为Packet对象分配内存<BR>lpPacket=(LPPACKET)GlobalAllocPtr(<BR>GMEM_MOVEABLE | GMEM_ZEROINIT,<BR>sizeof(PACKET)<BR>);<BR>if (lpPacket==NULL) {<BR>ODS("Packet32: PacketAllocateSendPacket: GlobalAlloc Failed\n");<BR>return NULL;<BR>}<BR>// 建立一个事件，这个事件将在操作完成后激活<BR>lpPacket-&gt;OverLapped.hEvent=CreateEvent(<BR>NULL,<BR>FALSE,<BR>FALSE,<BR>NULL<BR>);<BR>if (lpPacket-&gt;OverLapped.hEvent==NULL) {<BR>ODS("Packet32: PacketAllocateSendPacket: CreateEvent Failed\n");<BR>GlobalFreePtr(lpPacket);<BR>return NULL;<BR>}<BR>return lpPacket;<BR>}<BR>l PacketInitPacket<BR>函数PacketInitPacket初始化packet对象，即将packet对象中的buffer设置为传递的buffer指针。<BR><BR>VOID<BR>PacketInitPacket(<BR>LPPACKET lpPacket,<BR>PVOID Buffer,<BR>UINT Length<BR>)<BR>{<BR>lpPacket-&gt;Buffer=Buffer;<BR>lpPacket-&gt;Length=Length;<BR>}<BR><BR>l PacketReceivePacket<BR>函数PacketReceivePacket调用驱动程序的相应的入口点来从网络上读取一个数据包。这个操作是通过调用ReadFile函数来实现的。<BR><BR>BOOLEAN<BR>PacketReceivePacket(<BR>LPADAPTER AdapterObject,<BR>LPPACKET lpPacket,<BR>BOOLEAN Sync,<BR>PULONG BytesReceived<BR>)<BR>{<BR>BOOLEAN Result;<BR>// 设置偏移量(Offset)为0<BR>lpPacket-&gt;OverLapped.Offset=0;<BR>lpPacket-&gt;OverLapped.OffsetHigh=0;<BR>if (!ResetEvent(lpPacket-&gt;OverLapped.hEvent)) {<BR>return FALSE;<BR>}<BR>// 调用ReadFile 来读取一个数据包<BR>Result=ReadFile(<BR>AdapterObject-&gt;hFile,<BR>lpPacket-&gt;Buffer,<BR>lpPacket-&gt;Length,<BR>BytesReceived,<BR>&amp;lpPacket-&gt;OverLapped<BR>);<BR>if (Sync) {<BR>// 调用者设定为未接收到数据包将等待，即同步调用<BR>// 所以我们使用Overlapped中的同步对象来等待数据包<BR>Result=GetOverlappedResult(<BR>AdapterObject-&gt;hFile,<BR>&amp;lpPacket-&gt;OverLapped,<BR>BytesReceived,<BR>TRUE<BR>);<BR>}<BR>else<BR>{<BR>// 如果调用者不想等待，则直接退出，他们会调用PacketWaitPacket来获得这次请<BR>// 求的最终结果<BR>Result = TRUE;<BR>}<BR>return Result;<BR>}<BR><BR><BR>具体应用<BR>当我们实现了网络监视器后，成功地从网络上截获数据之后，怎么办呢？在下篇中，我将讲如何具体应用。<BR><BR><BR>参考资料<BR><BR>1． Windows NTDDK Help<BR>2． Windows NTDDK Packet.sys Sample<BR><BR>首先，我声明一点，我们的网络监视功能是不能够阻止系统的一般协议栈对数据包的发送和接收的，它只是在比协议栈更低层次的地方(即网卡驱动程序的上端)获得了进入机器的数据包的一个"复本"，而"源本"则按照正常的流程向上传递给了相应的协议，"截获"这个词可能会让大家产生误解，我们的监视器只能实现"拷贝"这个功能，但说"拷贝"确实不太舒服，所以以后我还是使用"截获"这个词。<BR>　　当我们完成了一个能够成功地截获网上数据包的监视器了，但是这只是我们实现监视器的基础，还有许多工作要做，比如，当监视器截获数据包时，下一步应该干什么呢？什么事都不做当然不是目的。而且，我们不必要也不应该截获所有的数据包，我们要有目的的过滤那些需要的数据包，否则我们将看着海量的数据包而无所适从。<BR>下面我就从过滤数据包、增加功能和优化性能三个方面谈谈怎么在应用层实践网络监视。 <BR>1．过滤数据包<BR><BR>　　根据用户的需要过滤拷贝的数据包，提供给分析者分析，这可能是网络监视器的所能增加的最基本的功能了。要实现过滤，使用者必须要有网络的基本概念，特别要了解以太网帧的结构和IP，TCP/UDP等等数据包是如何封装在一个帧中的，这一节讲的是就是如何根据自己的需要识别各种数据包的结构并过滤它。<BR><BR>　　为了在一个分层次的网络上传输数据，我们将数据从我们的应用程序传送到一个协议栈上，当数据在栈上一层一层地向下传送时，每一层的相应协议将把上一层传送下来的数据封装为自己的格式，举一个最普通的数据传递过程，即应用-&gt;TCP-&gt;IP-&gt;以太网流程，如下图所示：<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006313163850560.JPG" border=0><BR>　　在图中我们可以清楚地看到TCP/IP协议栈及以太网中的数据传送的层次关系：当我们在应用程序（一般应用有HTTP、FTP等等协议）中将应用数据（包括用户数据和应用首部）向网络传送，它首先到达TCP层，TCP协议根据应用层的要求在TCP首部填写好各个字段，比如端口号、序号、标志等等，重要的一个步骤是填写数据校验和到校验和字段，然后将包括TCP首部的段（数据包在TCP协议层称为段segment）向协议栈的下一层即IP层传送；IP层则与TCP层一样，填写IP首部的各个字段，比如地址、协议类型等等，然后将在头部包括IP首部和TCP首部的整个数据报（数据包在IP协议层称为数据报datagram）向下传送；到了以太网驱动程序，他将继续进行封装工作，将以太网首部和以太网尾部添加到从IP层传下来的数据报上。 <BR><BR>下面我们从外向内看各个封装的格式。<BR><BR>l 以太网帧首部<BR><BR>　　以太网帧的首部的组成是：6字节的目的硬件地址、6字节的源硬件地址和2字节的类型字段。如下图所示。对于类型字段我们主要使用以下几种：<BR><BR>协议 类型字段<BR>IP 0800h<BR>ARP 0806h<BR>RARP 0835h<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006313164759302.JPG" align=middle border=0><BR><BR>l IP首部<BR><BR>IP的全称是Internet Protocol即网际协议，这个协议是TCP/IP协议族中的核心协议。下面是它的数据报格式：<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006313164847862.JPG" align=middle border=0><BR>从图中可以看出，如果IP数据报没有选项的话，那么IP首部有20字节。对网络监视器来说，IP首部中各字段中重要的有：IP地址、协议类型、总长度。<BR>协议类型说明是什么协议(TCP,UDP,ICMP,IGMP)向它传递数据。下面是各个主要协议的代码：<BR>协议类型 协议代码（十进制）<BR>TCP 6<BR>UDP 17<BR>ICMP 1<BR>IGMP 2<BR>所以我们可以根据协议的代码来判断数据报内部封装的数据是属于什么协议。<BR><BR>下面的四个协议(ICMP、IGMP、TCP、UDP)都是封装在IP数据报中的。<BR><BR>l ICMP首部<BR><BR>ICMP的全称是Internet Control Message Protocol即网间控制报文协议。著名的Ping程序用的就是这个协议。它的首部结构见下图。<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/200631316509832.JPG" align=middle border=0><BR><BR>l IGMP首部<BR><BR>IGMP的全称是Internet Group Manage Protocol即因特网组管理协议。它是用来支持主机和路由器进行多播的协议。<BR><BR><BR>l TCP首部<BR><BR>TCP的全称是Transport Control Protocol即传输控制协议。它是非常重要的协议。我们的FTP，HTTP，TELNET等我们经常使用的应用都是使用TCP来传输的。它提供一种面向连接的、可靠的字节流服务。下面是它的首部的结构。<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006313164455542.JPG" border=0><BR>如图所示，TCP首部长20字节，包括了源端口、目的端口、序号、确认序号、首部长度（以四字节记）、六个标志字段、窗口大小、校验和等等。<BR>六个标志字段的意义见下表：<BR><BR>标志 意义<BR>URG 紧急指针(urgent pointer)有效<BR>ACK 确认序号有效<BR>PSH 接收方应该尽快将这个报文段交给应用层<BR>RST 重建连接<BR>SYN 同步序号用来发起一个连接<BR>FIN 发端完成发送任务<BR><BR><BR>l UDP首部<BR><BR>UDP的全称是User Datagram Protocol即用户数据报协议，与TCP区别，它是面向无连接应用的协议，象我们的OICQ、ICQ等聊天软件都是用的UDP协议。下面是UDP首部的结构。<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/200631316539718.JPG" align=middle border=0><BR>我们可以看到，UDP首部比TCP首部要简单得多，这是因为UDP是无连接的，比TCP的有连接中双方复杂的交互要简单，它并不保证数据传输的质量，但是我们可以在更高层的应用中自己进行质量保证。<BR><BR>l HTTP<BR><BR>　　HTTP的全称是Hyper Text Transfer Protocol。我们浏览网页用的就是这个协议。HTTP数据是在TCP包中的，而且一般来说网页服务是在80或8080端口。所以如果你只需要分析浏览网页的情况，只需要截获端口号有80或8080的TCP包就可以了。更进一步，我们需要分析HTTP协议中请求的内容。<BR>　　我们可能需要得到用户浏览网页的URL地址。假设我们现在得到了包含在TCP包中的HTTP头信息。任何我们在浏览器里对HTTP服务器发送的请求都是GET或POST请求中的一种。浏览器在HTTP头里添加了与请求及系统相关的信息然后将请求发送给相应的服务器。那些信息当然包括了我们想要的URL。所以我们分析HTTP头就可以得到URL。下面是一个正常的包含于HTTP头中的URL：<BR>GET / HTTP/1.1<BR>　　上面的请求是得到服务器的主页（即默认页）的HTTP请求。"/"表示服务器的主页，后面的"HTTP/1.1"表示这是HTTP的1.1版本。这是现在的主流版本，也有1.0的老版本。<BR>下面是一个我们访问服务器上其他的网页的请求。<BR>GET /source/index.html HTTP/1.1<BR>上面的请求是得到"/source/index.html"的请求。<BR>从上面我们可以知道如何解析HTTP头。<BR><BR>l 小结<BR>通过上面对数据格式的介绍，我们可以轻松灵活地进行数据包的过滤。<BR><BR>2．增强我们的程序的功能<BR><BR>　　我们当然不会满足于实现仅仅能够捕获数据包的简单的应用程序，要不是，我们干嘛这么辛苦编程呢，直接用Netxray等软件得了，我们的目的是能够让程序实现自己的功能。一个有意思的功能就是能够得到局域网上他人使用的代理服务器，实现方法很简单，别人使用代理服务器的连接特征一般是在服务器返回给用户端的HTTP头中有"Proxy-Connection"关键字存在。<BR>下面我从通过实现一个访问限制器讲讲怎么增强程序的功能。<BR>由于局域网的特殊性，我们可以实现一个局域网的访问限制器，可以限制网上其他用户对因特网的访问权限。要实现这样的功能，我们先讲讲如何通过协议驱动程序发送数据包。<BR>使用Packet32.dll中的函数PacketSendPacket来发送数据包。下面是这个函数的定义：<BR>BOOL<BR>PacketSendPacket(<BR>LPADAPTER AdapterObject, // 我们使用PacketOpenAdapter打开的网络适配卡对象<BR>LPPACKET lpPacket, // 使用PacketAllocatePacket等函数建立的数据包对象，<BR>BOOLEAN Sync // 是否同步<BR>);<BR><BR>如果函数发送数据包成功，则返回True，否则返回False。<BR>　　下面我讲讲构建数据包中需要注意的地方。<BR>　　首先是字与双字在各种系统中内部存储的方式的不同，在Windows中字与双字是高位在低地址排列的，而网络传输的标准是低位在低地址排列，比如一个十进制数字4660在Windows系统中存储成3412h，而在网络上表示是1234h。所以我们在设置或读取协议首部中有关用字或双字表示（一般象TCP中的端口、序号，而IP地址则不是）的字段时要切记转换他们的排列顺序。下面是一个转换字排列顺序的转换算法：<BR><BR>WORD SwapWord(WORD WordToReverse)<BR>{<BR>WORD lo,hi;<BR>WORD result;<BR><BR>lo= WordToReverse &amp; 0xff;<BR>hi= WordToReverse &amp; 0xff00;<BR>lo=lo&lt;&lt;8;<BR>hi=hi&gt;&gt;8;<BR>result=hi | lo;<BR><BR>return result;<BR>}<BR><BR>　　在我们建立发送包的过程中，除了设置包中IP首部、TCP首部中各种字段为我们需要的值，一个非常重要的工作是计算TCP、UDP、IP的校验和。我们遇到的校验和计算就是把一个范围的数据按字（16 bit，WORD，即两个字节）反码相加，如果数据不是字对齐的，则将在最后补上一个填充字节0使之字对齐再进行计算（在IP校验和计算中，由于只要计算IP首部，所以没可以出现这种情况，但是我们在后面的TCP、UDP校验和计算中碰到这种情况），以上计算得到的结果就是校验和。下面是一个公用校验和计算函数，它可以用在IP、TCP、UDP校验和的计算中：<BR><BR>WORD CheckSum(WORD *addr,WORD len)<BR>{<BR>DWORD lSum;<BR>WORD wOddByte;<BR>WORD ChecksumAnswer; <BR><BR>lSum=0l;<BR><BR>while(len&gt;1) {<BR>lSum+= *addr++;<BR>len-=2;<BR>}<BR><BR>if(len==1) {<BR>wOddByte=0;<BR>*((unsigned char*)&amp;wOddByte)=*(unsigned char*)addr;<BR>lSum+=wOddByte;<BR>}<BR><BR>lSum=(lSum&gt;&gt;16)+(lSum&amp;0xffff);<BR>lSum+=(lSum&gt;&gt;16);<BR>ChecksumAnswer=(unsigned int)~lSum;<BR><BR>return CheckSumAnswer;<BR>}<BR><BR>　　IP首部的校验和只计算IP首部的数据，而UDP校验和是计算整个UDP首部和UDP数据。<BR>　　UDP的校验和是可选的，尽管UDP校验和的基本计算方法与上面描述的IP首部校验和计算方法相类似（16 bit 字的二进制反码和），但是它们之间存在不同的地方。首先，UDP数据报的长度可以为奇数字节，但是校验和算法是把若干个16 bit 字相加。如前所述，我们可以在最后增加填充字节0 ，这只是为了校验和的计算（也就是说，可能增加的填充字节不被传送）。其次，UDP数据报包含一个12字节长的伪首部，它是为了计算校验和而设置的。伪首部包含IP首部一些字段。由于UDP可以不计算校验和，所以规定如果发送端没有计算校验和的话，校验和字段将设置为0。UDP数据报中的伪首部格式如下图所示。<BR><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/200631316539718.JPG" align=middle border=0><BR>　　TCP校验和的计算方法与UDP大致相同，只是TCP伪首部中的长度为16位TCP长度。而且TCP的校验和是必须计算的。<BR>　　另外在我们发送TCP报文段的时候要注意序号的顺序，不然发送的报文段将得不到对方的承认。<BR>　　知道了以上发送数据包的必要知识，我们现在可以使用发送数据包来进行应用了：比如，前面我提到了访问限制器，我们可以在截获了某用户的对以太网的非法访问后（可以通过对IP地址的检查或者对HTTP头中URL的检查来实现），根据截获的TCP包的序号重新构建一个伪装成从服务器发送的TCP包，其中TCP包中的RST标志设为1，将它发送到网上的话，他们建立的连接将被断开，所以就实现了阻止用户访问非法站点的功能。<BR>　　从上面的应用我们也看到了局域网的不安全性，每个结点都可以得到任何结点的网络信息，甚至可以轻松地阻断别人的网络连接，那种方法如果用在黑客手里，你也不能有如何防御的手段，幸好这只是在局域网上，如果有人能够在路由器上获得截获，那将是不幸的事情。<BR><BR>3．优化应用程序的性能<BR><BR>　　用过Netxray等网络监视器的读者都知道，如果在一个繁忙的网络上进行截获，而且不设置任何过滤，那得到的数据包是非常多的，可能在一秒钟内得到上千的数据包。如果应用程序不进行必要的性能优化，那么将会大量的丢失数据包，下面就是我对性能的一个优化方案。<BR>　　这个方案使用了多线程来处理数据包。在程序中建立一个公共的数据包缓冲池，这个缓冲池是一个LILO的队列。程序中使用三个线程进行操作：一个线程只进行捕获操作，它将从驱动程序获得的数据包添加到数据包队列的头部；另一个线程只进行过滤操作，它检查新到的队尾的数据包，检查其是否满足过滤条件，如果不满足则将其删除出队列；最后一个线程进行数据包处理操作，象根据接收的数据包发送新数据包这样的工作都由它来进行。上面三个线程中，考虑尽可能少丢失数据包的条件，应该是进行捕获操作的线程的优先级最高，当然具体问题具体分析，看应用的侧重点是什么了。<BR><BR>4．参考资料<BR>TCP/IP详解 卷1:协议 （本文的图摘自本书）<BR>IPMan from HiHint<BR></FONT></P>]]></description>
</item><item>
<title><![CDATA[windows驱动程序开发]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=12379</link>
<author>binaryluo</author>
<pubDate>2006/3/8 17:26:12</pubDate>
<description><![CDATA[<STRONG><FONT size=2>1.用户态驱动驱动程序和核心态驱动程序</FONT></STRONG><A><FONT size=2>　</FONT></A><A><FONT size=2>　</FONT></A><A><FONT size=2>　</FONT></A><FONT size=2> </FONT>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>下图描绘出了操作系统驱动程序的相关组成部分的概貌：</FONT></SPAN><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:wrapblock><?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><FONT face="Times New Roman"><FONT size=2> <v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></FONT></FONT></v:shapetype><v:shape id=_x0000_s1026 style="MARGIN-TOP: 20.4pt; Z-INDEX: 1; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 414.75pt; POSITION: absolute; HEIGHT: 256.5pt; TEXT-ALIGN: left; mso-position-horizontal: center; mso-position-horizontal-relative: text; mso-position-vertical-relative: text; mso-position-vertical: absolute" type="#_x0000_t75"><v:imagedata o:title="Windows组成" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.png"></v:imagedata><?xml:namespace prefix = w ns = "urn:schemas-microsoft-com:office:word" /><w:wrap type="topAndBottom"></w:wrap></v:shape></o:wrapblock></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006330181146322.GIF" border=0><BR style="mso-ignore: vglayout" clear=all></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN lang=EN-US><FONT face="Times New Roman">Windows</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动程序既可以运行在用户态也可以运行在核心模态。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 63.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用户态的驱动程序运行在非特权处理机模式（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">nonprivileged processor mode</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）上，其他一些被保护的子系统代码也运行在该模式上。用户态的驱动程序不能获得系统数据的存取权，除非调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Win32 API</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者系统服务。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 63.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">核心态驱动程序作为操作系统的一个组成部分被执行——支持一个或多个受保护的子系统的操作系统底层组件。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>用户态和核心态驱动程序有不同的结构，不同的入口点和不同的系统接口。一个设备是需要一个用户态驱动程序还是需要一个核心态驱动程序依赖于该设备的类型和操作系统对它提供的支持。</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一些设备驱动程序可以完全地或部分地运行在用户态。用户态驱动程序没有堆栈空间的限制，可以访问</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Win32 API</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，并且容易调试。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">大多设备驱动程序运行在核心态。核心态驱动程序可以完成某些受保护的操作，并且可以访问用户态驱动程序不能访问的系统结构体（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">system sturcture</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）。然而，访问权限的提高当然也要付出相应的代价——调试的艰难，系统随时面临毁坏的危险。当代码运行在有特权的核心态环境中时，操作系统对代码所请求的数据的完整性和有效性的检查将大大减少。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为了方便，应该用高级语言（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">high-level language</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）来编写驱动程序，通常，</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">C</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">适合用来编写核心态驱动程序，</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">C</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">C++</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">则适合用于编写用户态驱动程序。</SPAN></FONT></P><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动开发一般分为六步，在下面列出，每一步在</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DDK</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中都有相关部分进行阐述。</SPAN></FONT></P>
<UL>
<LI>
<DIV class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>第一步：理解驱动程序和操作系统基础</FONT></SPAN></DIV></LI>
<LI>
<DIV class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>第二步：确定特定设备驱动程序的需求</FONT></SPAN></DIV></LI>
<LI>
<DIV class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>第三步：做一个驱动程序设计方案</FONT></SPAN></DIV></LI>
<LI>
<DIV class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>第四步：构建、测试和调试驱动程序</FONT></SPAN></DIV></LI>
<LI>
<DIV class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>第五步：提供一个驱动程序包</FONT></SPAN></DIV></LI>
<LI>
<DIV class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>第六步：发布驱动程序</FONT></SPAN></DIV></LI></UL>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.设备对象和设备栈</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></B></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.1介绍设备对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">操作系统用设备对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">device object</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）表示设备。每一个设备都有一个或多个设备对象与之相关联。设备对象提供了在设备上的所有操作。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2>核心态驱动程序中，每个设备必须至少创建一个设备对象，下面两种情况除外：</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">与类（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">class</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）或端口设备相关的微驱动程序不必创建它自己的设备对象。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">特定类型子系统的设备驱动程序的设备对象由子系统创建。例如：</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">NDIS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">小端口驱动。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一些设备对象并不表示物理设备。一个唯软件驱动程序（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">software-only driver</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，处理</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">I/O</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">请求，但是不把这些请求传递给硬件）也必须创建表示它的操作的设备对象。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备常常由多个设备对象所表示，每一个设备对象在驱动程序栈（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">driver stack</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）中对应一个驱动程序来管理设备的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">I/O</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">请求。一个设备的所有设备对象被组织成一个设备栈（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">device stack</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）。无论何时，一个操作都在一个设备上被完成，系统把</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IRP</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">I/O request packet</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）数据结构体传递给设备栈中顶部设备的驱动程序。每一个驱动或者处理</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IRP</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，或者把它传递给设备栈中下一个设备对象的驱动程序。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备对象由</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DEVICE_OBJECT</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">结构体表示，它被对象管理器（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Object Manager</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）所管理。对象管理器提供为设备对象提供与其他系统对象相同的功能。特别地，一个设备对象可以被命名，并且一个被命名的设备对象可以有一个句柄。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><o:wrapblock><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype></o:wrapblock><BR style="mso-ignore: vglayout" clear=all><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 系统为每一个设备对象提供专门的存储空间，被成作设备扩展（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">device extension</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">），它可以用作特定设备的存储空间。设备扩展同设备对象一起被创建和释放。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下图描述了设备对象和</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">I/O</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">管理器之间的关系：</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><IMG style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://blogger.org.cn/blog/uploadfile/2006330181248989.GIF" border=0></SPAN></FONT></P></BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT size=2></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><STRONG><FONT size=2><SPAN><FONT face="Times New Roman"><FONT face=宋体>2.2</FONT>Windows</FONT>驱动模型（<FONT face="Times New Roman">WDM</FONT>）设备对象和设备栈</SPAN></FONT></STRONG></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><STRONG><FONT size=2><SPAN></SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></STRONG>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo1; tab-stops: list 39.0pt"><FONT size=2><FONT face="Times New Roman"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2.2.1．<SPAN style="FONT: 7pt 'Times New Roman'"> </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US>WDM</SPAN></B></FONT><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备对象的类型</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">有三种类型的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备对象：</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; TEXT-INDENT: 0cm; mso-list: l1 level2 lfo1; tab-stops: list 63.0pt"><FONT size=2><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore"><FONT face="Times New Roman">1)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></FONT></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">物理设备对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">PDO</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）——表示一个总线驱动程序的总线设备。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; TEXT-INDENT: 0cm; mso-list: l1 level2 lfo1; tab-stops: list 63.0pt"><FONT size=2><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore"><FONT face="Times New Roman">2)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></FONT></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数设备对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">FDO</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）——表示一个函数驱动程序的设备。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; TEXT-INDENT: 0cm; mso-list: l1 level2 lfo1; tab-stops: list 63.0pt"><FONT size=2><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore"><FONT face="Times New Roman">3)<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></FONT></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">过滤器设备对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">filter DO</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）——表示一个过滤器驱动程序的设备。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这三种设备对象都是</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DEVICE_OBJECT</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类型，但是用法不同并且有不同的设备扩展。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo1; tab-stops: list 39.0pt"><FONT size=2><FONT face="Times New Roman"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2.2.2．<SPAN style="FONT: 7pt 'Times New Roman'"> </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US>WDM</SPAN></B></FONT><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备对象的例子</SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo1; tab-stops: list 39.0pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo1; tab-stops: list 39.0pt"><FONT size=2><FONT face="Times New Roman"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2.2.3．<SPAN style="FONT: 7pt 'Times New Roman'"> </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US>WDM</SPAN></B></FONT><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备对象何时被创建</SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo1; tab-stops: list 39.0pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo1; tab-stops: list 39.0pt"><FONT size=2><FONT face="Times New Roman"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2.2.4．<SPAN style="FONT: 7pt 'Times New Roman'"> </SPAN></SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US>WDM</SPAN></B></FONT><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备栈的例子</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US><o:p><FONT face="Times New Roman" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><B style="mso-bidi-font-weight: normal"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.3创建一个设备对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 驱动程序调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来创建它们的设备对象。当驱动程序创建一个设备对象时，要提供下列信息给</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：</SPAN></FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l2 level1 lfo3; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设备的设备扩展（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">device extension</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的大小。设备扩展是一块系统分配的存储区域，驱动程序可以使用这块区域作为特定设备的存储空间。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个系统定义的常量，指明设备对象表示的设备类型（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DeviceType</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个或多个</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">ORed</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，系统定义的常量，它指明了设备的特征。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个被叫做</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Exclusive</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的布尔值（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Boolean value</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">），它指明了设备对象的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Flags</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中的一位是否应该被设置成</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DO_EXCLUSIVE</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">——表明驱动服务于一个独立的设备，例如视频，串行，并行或声音设备。</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动必须设置</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Exclusive</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">FALSE</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个指向驱动程序的驱动对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">driver object</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的指针。一个</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数或过滤器驱动程序接收指向它的驱动对象的指针作为它的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">AddDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数的参数。所有的驱动程序在它们的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DriverEntry</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数中接收到一个只想驱动对象的指针。系统使用这个指针与相应的设备对象关联起来。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个指向以</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">0</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中止符结尾的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Unicode</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字符串（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DeviceName</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的指针，该指针是可选的。除了总线驱动程序，</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动程序不提供设备名称。</SPAN></FONT></P></BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 如果调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">成功，</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">I/O</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">管理器将为设备对象本身和其它所有与设备对象相关的数据结构提供存储空间，包括设备扩展，它初始化的时候为</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">0</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.3.1为</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数和过滤器驱动程序创建设备对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 除了总线驱动程序以外的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动程序都调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来创建它们的设备对象。大多数的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动程序在它们的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">AddDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数里来创建设备对象。有些驱动程序，例如磁盘驱动程序，从分派函数（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">dispatch routine</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 除非是</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DDK</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">说明文档里特别指定的设备类型，否则，你的驱动程序应该在它的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">AddDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数中创建设备对象。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"></SPAN></FONT>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.3.2为</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总线驱动程序创建设备对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 当一个</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总线驱动程序为响应</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IRP_MN_QUERY_DEVICE_RELATIONS</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而列出新设备时，如果类型是</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">BusRelations</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，它将创建一个物理设备对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">PDO</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下列规则决定了一个总线驱动程序是调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">还是调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来创建一个设备对象：</SPAN></FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l3 level1 lfo4; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果设备可以在原始模式（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">raw mode</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）下使用，那么必须调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l3 level1 lfo4; tab-stops: list 42.0pt"><FONT size=2><SPAN lang=EN-US style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><SPAN style="mso-list: Ignore">l<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果设备不能在原是模式下使用，那么总线驱动程序既可以调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，也可以调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。当对于总线上的设备的默认系统安全性足够的时候可以调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">；调用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以指定更严格的安全描述符。</SPAN></FONT></P></BLOCKQUOTE>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.3.3为非</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动程序创建设备对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 非</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">WDM</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动程序通常使用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来创建无名的设备对象，使用</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">IoCreateDeviceSecure</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来创建有名的设备对象。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US><o:p><FONT face="Times New Roman" size=2>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN-US><o:p><FONT face="Times New Roman" size=2></FONT></o:p></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><B style="mso-bidi-font-weight: normal"><FONT size=2><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">2.4初始化一个设备对象</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></FONT></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><FONT size=2><SPAN lang=EN-US><FONT face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IoCreateDevice</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">将返回一个指向设备对象（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">DeviceObject</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的指针给调用者，这个设备对象包含一个指向设备扩展（</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">device extension</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）的指针，驱动程序必须为它们的物理的、逻辑的、或虚拟的设备创建各自的区域。</SPAN></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><FONT size=2></FONT></SPAN></P>]]></description>
</item><item>
<title><![CDATA[考研？考验！]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=12213</link>
<author>binaryluo</author>
<pubDate>2006/3/4 0:16:48</pubDate>
<description><![CDATA[
<P>&nbsp;&nbsp;&nbsp; 今天查到考研的成绩了。还不错，虽然比自己之前估计的稍差点，但还是感觉不错了。</P>
<P>&nbsp;&nbsp;&nbsp; 经历了今天才发觉等成绩才是比考试更刺激呢。特别是在输入自己考号的时候，心里面是相当的澎湃啊——既希望考起，又怕考不起。那种矛盾心理真的是受不了。还好这种压力只是几秒钟，最多几分钟，不然人的寿命肯定会缩短一二十年。查到成绩后到是平静了，但还是掩抑不住的兴奋。（估计今晚可能会难眠，想很多问题）</P>
<P>&nbsp;&nbsp;&nbsp; 真不敢去想万一考砸了自己会怎么样，也不愿意去想。真但愿所有考研的同学都能如愿以偿就好了……</P>
<P>&nbsp;&nbsp;&nbsp; 考研其实不仅是考知识，更是一种考验！考验人的耐心和毅力，也考验人的心理承受能力。</P>]]></description>
</item><item>
<title><![CDATA[C#操作Word]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=11813</link>
<author>binaryluo</author>
<pubDate>2006/2/18 12:36:29</pubDate>
<description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; C#操作Office套件的时候都需要用到COM组件，需要在项目里添加相应的COM组件。用C#在Word里查找指定关键字的方法有两种：Selection对象和Range对象。<br>
<br>&nbsp;&nbsp;&nbsp;&nbsp; Selection对象的用法：<br>
<div class="HtmlCode" style="cursor: pointer;" ;="" title="点击运行该代码！" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();">
&#8226; // C#<br>
&#8226; internal void SelectionFind()<br>
&#8226; {<br>
&#8226; string strFind = "find me";<br>
&#8226; Word.Find fnd = ThisApplication.Selection.Find;<br>
&#8226; fnd.ClearFormatting();<br>
&#8226; fnd.Text = strFind;<br>
&#8226; object missingValue = Type.Missing;<br>
&#8226;<br>
&#8226; if (fnd.Execute(ref missingValue, ref missingValue,<br>
&#8226; ref missingValue, ref missingValue, ref missingValue,<br>
&#8226; ref missingValue, ref missingValue, ref missingValue,<br>
&#8226; ref missingValue, ref missingValue, ref missingValue,<br>
&#8226; ref missingValue, ref missingValue, ref missingValue,<br>
&#8226; ref missingValue))<br>
&#8226; {<br>
&#8226; MessageBox.Show("Text found.");<br>
&#8226; }<br>
&#8226; else<br>
&#8226; {<br>
&#8226; MessageBox.Show("The text could not be located.");<br>
&#8226; }<br>
}<br> </div>
&nbsp;&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;&nbsp; Range对象的用法：<br>
<div class="HtmlCode" style="cursor: pointer;" ;="" title="点击运行该代码！" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// C#<br>
internal void RangeFind()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Word.Range rng = ThisDocument.Paragraphs[2].Range;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Word.Find fnd = rng.Find;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fnd.ClearFormatting();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; object missingValue = Type.Missing;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; object findStr = "find me";<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (fnd.Execute(ref findStr, ref missingValue, ref missingValue,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ref missingValue, ref missingValue, ref missingValue))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox.Show("Text found.");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox.Show("Text not found.");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rng.Select();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br></div><br>
&nbsp;&nbsp;&nbsp;&nbsp; 下面是自己写的一段完整的代码，功能：在一个指定的Word文档中查找指定的关键字，并打印出包含该关键字的段落。使用的Range对象。<br>
<div class="HtmlCode" style="cursor: pointer;" ;="" title="点击运行该代码！" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();"><br>
using System;<br>
using System.Collections;<br>
using Word;<br>
<br>
namespace SearchWordDoc<br>
{<br>
&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<br>
&nbsp;&nbsp;&nbsp; /// SearchWordDoc's summary<br>
&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<br>
&nbsp;&nbsp;&nbsp; public class SearchWordDoc<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // search word in document.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // strName is the document name which is searched.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // strFind is the key word or phrase.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // return the match paragraphs.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public ArrayList swd(string strFName, string strFind)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ArrayList textsFound = new ArrayList();&nbsp; // matched texts<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; object missingValue = Type.Missing;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
Word.ApplicationClass wdApp = null;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //
Word Application object<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; object fName = strFName as object;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; wdApp = new
ApplicationClass();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // create a Word
application object<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; Word.Document wdDoc = wdApp.Documents.Open(ref
fName, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ref missingValue, ref
missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ref missingValue, ref
missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ref missingValue, ref
missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ref missingValue, ref
missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ref missingValue, ref
missingValue); // open a Word object<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; // the Word object has paragraphs or not<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if (wdDoc.Paragraphs != null &amp;&amp;
wdDoc.Paragraphs.Count &gt; 0)<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; int count =
wdDoc.Paragraphs.Count;&nbsp; // the number of doc paragraphs<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Word.Range
rng;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Word.Range object<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Word.Find
fnd;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Word.Find object<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine("There are {0}
paragraphs in document '{1}'.", count, strFName);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 1; i &lt;= count; ++
i)&nbsp;&nbsp;&nbsp; // search key words in every paragraphs<br>
&nbsp;&nbsp;&nbsp; &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;&nbsp;&nbsp; rng =
wdDoc.Paragraphs[i].Range;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fnd = rng.Find;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fnd.ClearFormatting();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fnd.Text =
strFind;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if
(fnd.Execute(ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ref missingValue, ref missingValue, ref missingValue,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ref missingValue))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &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;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // if find the matched paragrahps, add it into the
textsFound ArrayList.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; textsFound.Add("[" + i.ToString() + "] " +
wdDoc.Paragraphs[i].Range.Text.Trim());<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &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; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; catch (NullReferenceException e)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine(e.ToString());<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; wdApp.Quit(ref missingValue, ref missingValue, ref
missingValue);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; catch (Exception e)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine(e.ToString());<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; wdApp.Quit(ref missingValue, ref missingValue, ref
missingValue);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // release the Word application object<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; wdApp.Quit(ref missingValue, ref missingValue, ref missingValue);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return textsFound;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // Display usage<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void usage()<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine("\nUsage: SearchWordDoc doc_name string_found " +<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; "[start_paragraph_NO.]\n\t\t&nbsp;&nbsp;&nbsp;&nbsp;
[end_paragraph_NO.]");<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // Print the result<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void printText(ArrayList lst)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (lst == null)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine("Error: Null ArrayList.\n");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int len = lst.Count;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; len; ++ i)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine("\t" + lst[i] as string);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine("\nThere are {0} records.", len);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // Function Main<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public static void Main(string[] args)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ArrayList textsFound = new ArrayList();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SearchWordDoc sobject = new SearchWordDoc();<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; switch (args.Length)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 0:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 1:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sobject.usage();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 2:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; textsFound = sobject.swd(args[0],
args[1]);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Console.WriteLine("Search
Result:\n");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sobject.printText(textsFound);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; default:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sobject.usage();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br></div><br>
C#对Word的操作和对Excel等的操作方法很相似。具体的对象说明可以参考.NET SDK。<br>]]></description>
</item><item>
<title><![CDATA[【转】Sniffer含义及工作原理]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=11796</link>
<author>binaryluo</author>
<pubDate>2006/2/17 13:41:00</pubDate>
<description><![CDATA[
<DIV style="TEXT-ALIGN: left">
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT class=f14 id=zoom style="FONT-WEIGHT: bold">一.有关sniffer及sniffer的含义</FONT></FONT></P>
<P><FONT size=2><FONT class=f14 id=zoom>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sniffers(嗅探器)几乎和internet有一样久的历史了.Sniffer是一种常用的收集有用数据方法，这些数据可以是用户的帐号和密码，可以是一些商用机密数据等等。随着Internet及电子商务的日益普及,Internet的安全也越来越受到重视。在Internet安全隐患中扮演重要角色之一的Sniffer以受到越来越大的关注，所以今天我要向大家介绍一下介绍Sniffer以及如何阻止sniffer。　　</FONT></FONT></P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT size=2><FONT class=f14 id=zoom>大多数的黑客仅仅为了探测内部网上的主机并取得控制权，只有那些"雄心勃勃"的黑客，为了控制整个网络才会安装特洛伊木马和后门程序，并清除记录。他们经常使用的手法是安装sniffer。<BR><BR>　　在内部网上，黑客要想迅速获得大量的账号（包括用户名和密码），最为有效的手段是使用"sniffer"程序。这种方法要求运行 Sniffer程序的主机和被监听的主机必须在同一个以太网段上，故而在外部主机上运行sniffer是没有效果的。再者，必须以root的身份使用 sniffer程序，才能够监听到以太网段上的数据流。谈到以太网sniffer，就必须谈到以太网sniffing。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么什么是以太网sniffer呢?　　<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以太网sniffing是指对以太网设备上传送的数据包进行侦听，发现感兴趣的包。如果发现符合条件的包，就把它存到一个log文件中去。通常设置的这些条件是包含字"username"或"password"的包。<BR><BR>　　它的目的是将网络层放到promiscuous模式，从而能干些事情。Promiscuous模式是指网络上的所有设备都对总线上传送的数据进行侦听，并不仅仅是它们自己的数据。根据第二章中有关对以太网的工作原理的基本介绍，可以知道：一个设备要向某一目标发送数据时，它是对以太网进行广播的。一个连到以太网总线上的设备在任何时间里都在接受数据。不过只是将属于自己的数据传给该计算机上的应用程序。<BR><BR>　　利用这一点，可以将一台计算机的网络连接设置为接受所有以太网总线上的数据，从而实现sniffer。<BR><BR>　　sniffer通常运行在路由器，或有路由器功能的主机上。这样就能对大量的数据进行监控。sniffer属第二层次的攻击。通常是攻击者已经进入了目标系统，然后使用sniffer这种攻击手段，以便得到更多的信息。<BR><BR>　　sniffer除了能得到口令或用户名外，还能得到更多的其他信息，比如一个其他重要的信息，在网上传送的金融信息等等。sniffer几乎能得到任何以太网上的传送的数据包。黑客会使用各种方法，获得系统的控制权并留下再次侵入的后门，以保证sniffer能够执行。在Solaris2.x平台上， sniffer程序通常被安装在/usr/bin或/dev目录下。黑客还会巧妙的修改时间，使得sniffer程序看上去是和其它系统程序同时安装的。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; 大多数以太网sniffer程序在后台运行，将结果输出到某个记录文件中。黑客常常会修改ps程序，使得系统管理员很难发现运行的sniffer程序。<BR><BR>　　以太网sniffer程序将系统的网络接口设定为混合模式。这样，它就可以监听到所有流经同一以太网网段的数据包，不管它的接受者或发送者是不是运行sniffer的主机。程序将用户名、密码和其它黑客感兴趣的数据存入log文件。黑客会等待一段时间-----比如一周后，再回到这里下载记录文件。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 讲了这么多，那么到底我们可以用什么通俗的话来介绍sniffer呢？<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 计算机网络与电话电路不同，计算机网络是共享通讯通道的。共享意味着计算机能够接收到发送给其它计算机的信息。捕获在网络中传输的数据信息就称为sniffing（窃听）。<BR><BR>　　以太网是现在应用最广泛的计算机连网方式。以太网协议是在同一回路向所有主机发送数据包信息。数据包头包含有目标主机的正确地址。一般情况下只有具有该地址的主机会接受这个数据包。如果一台主机能够接收所有数据包，而不理会数据包头内容，这种方式通常称为"混杂"模式。<BR><BR>　　由于在一个普通的网络环境中，帐号和口令信息以明文方式在以太网中传输，一旦入侵者获得其中一台主机的root权限，并将其置于混杂模式以窃听网络数据，从而有可能入侵网络中的所有计算机。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一句话，sniffer就是一个用来窃听的黑客手段和工具。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="FONT-WEIGHT: bold">二、sniffer的工作原理</SPAN><BR><BR>　　通常在同一个网段的所有网络接口都有访问在物理媒体上传输的所有数据的能力，而每个网络接口都还应该有一个硬件地址，该硬件地址不同于网络中存在的其他网络接口的硬件地址，同时，每个网络至少还要一个广播地址。（代表所有的接口地址），在正常情况下，一个合法的网络接口应该只响应这样的两种数据帧：<BR><BR>　　1、帧的目标区域具有和本地网络接口相匹配的硬件地址。<BR>　　2、帧的目标区域具有"广播地址"。<BR><BR>　　在接受到上面两种情况的数据包时，nc通过cpu产生一个硬件中断，该中断能引起操作系统注意，然后将帧中所包含的数据传送给系统进一步处理。<BR><BR>　　而sniffer就是一种能将本地nc状态设成（promiscuous）状态的软件，当nc处于这种"混杂"方式时，该nc具备"广播地址"，它对所有遭遇到的每一个帧都产生一个硬件中断以便提醒操作系统处理流经该物理媒体上的每一个报文包。（绝大多数的nc具备置成promiscuous方式的能力）<BR><BR>　　可见，sniffer工作在网络环境中的底层，它会拦截所有的正在网络上传送的数据，并且通过相应的软件处理，可以实时分析这些数据的内容，进而分析所处的网络状态和整体布局。值得注意的是：sniffer是极其安静的，它是一种消极的安全攻击。<BR><BR>　　通常sniffer所要关心的内容可以分成这样几类：<BR>　　1、口令<BR>　　我想这是绝大多数非法使用sniffer的理由，sniffer可以记录到明文传送的userid和passwd.就算你在网络传送过程中使用了加密的数据，sniffer记录的数据一样有可能使入侵者在家里边吃肉串边想办法算出你的算法。<BR><BR>　　2、金融帐号<BR>　　许多用户很放心在网上使用自己的信用卡或现金帐号，然而sniffer可以很轻松截获在网上传送的用户姓名、口令、信用卡号码、截止日期、帐号和pin.<BR><BR>　　3、偷窥机密或敏感的信息数据<BR>　　通过拦截数据包，入侵者可以很方便记录别人之间敏感的信息传送，或者干脆拦截整个的email会话过程。<BR><BR>　　4、窥探低级的协议信息。<BR>　　这是很可怕的事，我认为，通过对底层的信息协议记录，比如记录两台主机之间的网络接口地址、远程网络接口ip地址、ip路由信息和tcp连接的字节顺序号码等。这些信息由非法入侵的人掌握后将对网络安全构成极大的危害，通常有人用sniffer收集这些信息只有一个原因：他正在进行一次欺诈，（通常的ip地址欺诈就要求你准确插入tcp连接的字节顺序号, 这将在以后整理的文章中指出）如果某人很关心这个问题，那么sniffer对他来说只是前奏，今后的问题要大得多。（对于高级的hacker而言，我想这是使用sniffer的唯一理由吧）<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="FONT-WEIGHT: bold">三.sniffer的工作环境</SPAN><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sniffer就是能够捕获网络报文的设备。嗅探器的正当用处在于分析网络的流量,以便找出所关心的网络中潜在的问题。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器来作出精确的问题判断。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 嗅探器在功能和设计方面有很多不同。有些只能分析一种协议，而另一些可能能够分析几百种协议。一般情况下，大多数的嗅探器至少能够分析下面的协议：<BR><BR>1.标准以太网<BR>2.TCP/IP<BR>3.IPX<BR>4.DECNet<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 嗅探器通常是软硬件的结合。专用的嗅探器价格非常昂贵。另一方面，免费的嗅探器虽然不需要花什么钱，但得不到什么支持。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 嗅探器与一般的键盘捕获程序不同。键盘捕获程序捕获在终端上输入的键值，而嗅探器则捕获真实的网络报文。嗅探器通过将其置身于网络接口来达到这个目的—— 例如将以太网卡设置成杂收模式。（为了理解杂收模式是怎么回事，先解释局域网是怎么工作的）。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据在网络上是以很小的称为帧(Ftame)的单位传输的帧由好几部分组成，不同的部分执行不同的功能。（例如，以太网的前12个字节存放的是源和目的的地址，这些位告诉网络：数据的来源和去处。以太网帧的其他部分存放实际的用户数据、TCP/IP的报文头或IPX报文头等等）。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 帧通过特定的称为网络驱动程序的软件进行成型，然后通过网卡发送到网线上。通过网线到达它们的目的机器，在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧，并告诉操作系统帧的到达，然后对其进行存储。就是在这个传输和接收的过程中，嗅探器会造成安全方面的问题。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; 每一个在LAN上的工作站都有其硬件地址。这些地址唯一地表示着网络上的机器（这一点于Internet地址系统比较相似）。当用户发送一个报文时，这些报文就会发送到LAN上所有可用的机器。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; 在一般情况下，网络上所有的机器都可以“听”到通过的流量，但对不属于自己的报文则不予响应（换句话说，工作站A不会捕获属于工作站B的数据，而是简单的忽略这些数据）。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果某在工作站的网络接口处于杂收模式，那么它就可以捕获网络上所有的报文和帧，如果一个工作站被配置成这样的方式，它（包括其软件）就是一个嗅探器。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; 嗅探器可能造成的危害：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.嗅探器能够捕获口令<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.能够捕获专用的或者机密的信息<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.可以用来危害网络邻居的安全，或者用来获取更高级别的访问权限<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; 事实上，如果你在网络上存在非授权的嗅探器就以为着你的系统已经暴露在别人面前了。（大家可以试试天行2的嗅探功能）<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp; 一般我们只嗅探每个报文的前200到300个字节。用户名和口令都包含在这一部分中，这是我们关心的真正部分。工人，也可以嗅探给定接口上的所有报文，如果有足够的空间进行存储，有足够的那里进行处理的话，将会发现另一些非常有趣的东西……简单的放置一个嗅探器宾将其放到随便什么地方将不会起到什么作用。将嗅探器放置于被攻击机器或网络附近，这样将捕获到很多口令，还有一个比较好的方法就是放在网关上。如果这样的话就能捕获网络和其他网络进行身份鉴别的过程。这样的方式将成倍地增加我们能够攻击的范围。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="FONT-WEIGHT: bold"> 四.谁会使用sniffers</SPAN><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可能谁都回知道谁会使用sniffer，但是并不是每个使用它的人都是网络高手，因为现在有很多的sniffer都成了傻瓜似的了，前段时间用的最多的不外乎oicqsniffer。我想那些喜欢查好友ip的朋友都应该记得它吧。呵呵，我都使用过它，现在当然不用了啊！<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然系统管理员使用sniffer来分析网络信息交通并且找出网络上何处发生问题。一个安全管理员可以同时用多种sniffer,将它们放置在网络的各处,形成一个入侵警报系统。对于系统管理员来说sniffer是一个非常好的工具,但是它同样是一个经常被黑客使用的工具.骇客安装sniffer以获得用户名和账号,信用卡号码,个人信息,和其他的信息可以导致对你或是你的公司的极大危害如果向坏的方面发展。当它们得到这些信息后,骇客将使用密码来进攻其他的internet站点甚至倒卖信用卡号码。</FONT></FONT></DIV>]]></description>
</item><item>
<title><![CDATA[【转】什么是Sniffer]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=binaryluo&amp;id=11792</link>
<author>binaryluo</author>
<pubDate>2006/2/17 11:49:25</pubDate>
<description><![CDATA[<FONT size=2>人们谈到黑客攻击，一般所指的都是以主动方式进行的，例如利用漏洞或者猜测系统密码的方式对系统进行攻击。但是其实还有一类危害非常大的被动攻击方式往往为大家所忽视，那就是利用Sniffer进行嗅探攻击。<BR></FONT>
<DIV class=cnpaf align=left>
<P><FONT size=2>&nbsp;&nbsp; Sniffer，中文可以翻译为嗅探器，是一种威胁性极大的被动攻击工具。使用这种工具，可以监视网络的状态、数据流动情况以及网络上传输的信息。当信息以明文的形式在网络上传输时，便可以使用网络监听的方式来进行攻击。将网络接口设置在监听模式，便可以将网上传输的源源不断的信息截获。黑客们常常用它来截获用户的口令。据说某个骨干网络的路由器曾经被黑客攻人，并嗅探到大量的用户口令。本文将详细介绍Sniffer的原理和应用。<BR>一、Sniffer 原理</FONT></P>
<P><FONT size=2>1．网络技术与设备简介<BR>&nbsp;&nbsp;&nbsp; 在讲述Sni计er的概念之前，首先需要讲述局域网设备的一些基本概念。<BR>&nbsp;&nbsp;&nbsp; 数据在网络上是以很小的称为帧（Frame）的单位传输的，帧由几部分组成，不同的部分执行不同的功能。帧通过特定的称为网络驱动程序的软件进行成型，然后通过网卡发送到网线上，通过网线到达它们的目的机器，在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧，并告诉操作系统帧已到达，然后对其进行存储。就是在这个传输和接收的过程中，嗅探器会带来安全方面的问题。<BR>&nbsp;&nbsp;&nbsp; 每一个在局域网（LAN）上的工作站都有其硬件地址，这些地址惟一地表示了网络上的机器（这一点与Internet地址系统比较相似）。当用户发送一个数据包时，这些数据包就会发送到LAN上所有可用的机器。<BR>&nbsp;&nbsp;&nbsp; 在一般情况下，网络上所有的机器都可以“听”到通过的流量，但对不属于自己的数据包则不予响应（换句话说，工作站A不会捕获属于工作站B的数据，而是简单地忽略这些数据）。如果某个工作站的网络接口处于混杂模式（关于混杂模式的概念会在后面解释），那么它就可以捕获网络上所有的数据包和帧。</FONT></P>
<P><FONT size=2>2．网络监听原理<BR>&nbsp;&nbsp;&nbsp;&nbsp; Sniffer程序是一种利用以太网的特性把网络适配卡（NIC，一般为以太网卡）置为杂乱（promiscuous）模式状态的工具，一旦网卡设置为这种模式，它就能接收传输在网络上的每一个信息包。<BR>&nbsp;&nbsp;&nbsp; 普通的情况下，网卡只接收和自己的地址有关的信息包，即传输到本地主机的信息包。要使Sniffer能接收并处理这种方式的信息，系统需要支持BPF， Linux下需要支持SOCKET一PACKET。但一般情况下，网络硬件和TCP／IP堆栈不支持接收或者发送与本地计算机无关的数据包，所以，为了绕过标准的TCP／IP堆栈，网卡就必须设置为我们刚开始讲的混杂模式。一般情况下，要激活这种方式，内核必须支持这种伪设备Bpfilter，而且需要 root权限来运行这种程序，所以sniffer需要root身份安装，如果只是以本地用户的身份进人了系统，那么不可能唤探到root的密码，因为不能运行Sniffer。<BR>&nbsp;&nbsp; 基于Sniffer这样的模式，可以分析各种信息包并描述出网络的结构和使用的机器，由于它接收任何一个在同一网段上传输的数据包，所以也就存在着捕获密码、各种信息、秘密文档等一些没有加密的信息的可能性。这成为黑客们常用的扩大战果的方法，用来夺取其他主机的控制权</FONT></P>
<P><FONT size=2>3&nbsp; Snifffer的分类<BR>&nbsp;&nbsp;&nbsp;&nbsp; Sniffer分为软件和硬件两种，软件的Sniffer有 NetXray、Packetboy、Net&nbsp; monitor等，其优点是物美价廉，易于学习使用，同时也易于交流；缺点是无法抓取网络上所有的传输，某些情况下也就无法真正了解网络的故障和运行情况。硬件的Sniffer通常称为协议分析仪，一般都是商业性的，价格也比较贵。<BR>&nbsp;&nbsp;&nbsp;&nbsp; 实际上本文中所讲的Sniffer指的是软件。它把包抓取下来，然后打开并查看其中的内容，可以得到密码等。Sniffer只能抓取一个物理网段内的包，就是说，你和监听的目标中间不能有路由或其他屏蔽广播包的设备，这一点很重要。所以，对一般拨号上网的用户来说，是不可能利用Sniffer来窃听到其他人的通信内容的。</FONT></P>
<P><FONT size=2>4．网络监听的目的</FONT></P>
<P><FONT size=2>&nbsp; 当一个黑客成功地攻陷了一台主机，并拿到了root权限，而且还想利用这台主机去攻击同一网段上的其他主机时，他就会在这台主机上安装Sniffer软件，对以太网设备上传送的数据包进行侦听，从而发现感兴趣的包。如果发现符合条件的包，就把它存到一个LOg文件中去。通常设置的这些条件是包含字 “username”或“password”的包，这样的包里面通常有黑客感兴趣的密码之类的东西。一旦黑客截获得了某台主机的密码，他就会立刻进人这台主机。<BR>&nbsp;&nbsp;&nbsp;&nbsp; 如果Sniffer运行在路由器上或有路由功能的主机上，就能对大量的数据进行监控，因为所有进出网络的数据包都要经过路由器。<BR>&nbsp;&nbsp;&nbsp;&nbsp; Sniffer属于第M层次的攻击。就是说，只有在攻击者已经进入了目标系统的情况下，才能使用Sniffer这种攻击手段，以便得到更多的信息。<BR>&nbsp;&nbsp;&nbsp;&nbsp; Sniffer除了能得到口令或用户名外，还能得到更多的其他信息，比如一个重要的信息、在网上传送的金融信息等等。Sniffer几乎能得到任何在以太网上传送的数据包。<BR>&nbsp;&nbsp;&nbsp;&nbsp; Sniffer是一种比较复杂的攻击手段，一般只有黑客老手才有能力使用它，而对于一个网络新手来说，即使在一台主机上成功地编译并运行了 Sniffer，一般也不会得到什么有用的信息，因为通常网络上的信息流量是相当大的，如果不加选择地接收所有的包，然后从中找到所需要的信息非常困难；而且，如果长时间进行监听，还有可能把放置Sniffer的机器的硬盘撑爆。</FONT></P></DIV>]]></description>
</item>
</channel>
</rss>