﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-游戏人生-随笔分类-G游戏编程</title><link>http://www.cppblog.com/Fox/category/5794.html</link><description>游戏人生 != ( 人生 == 游戏 )</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 13:56:21 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 13:56:21 GMT</pubDate><ttl>60</ttl><item><title>编程之美：一摞烙饼的排序（未完成）</title><link>http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sun, 20 Apr 2008 06:59:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47659.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47659.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47659.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
<p>首先声明：本人没有解决掉这个问题。</p>
<p>相比第一道<a href="http://www.cppblog.com/Fox/archive/2008/04/17/control_cpu_using_curve.html" target=_blank>让CPU占用率曲线听你指挥</a>对Windows系统中CPU占有率概念的考察和对API的使用，以及第二道<a href="http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html" target=_blank>中国象棋将帅问题</a>对抽象建模的考察。<a href="http://book.csdn.net/bookfiles/656/10065620785.shtml" target=_blank>这道题目</a>才算是一道算法题吧？之前那两道尤其是<a href="http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html" target=_blank>中国象棋将帅问题</a>总有点脑筋急转弯的味道。</p>
<p>题目：<font color=#800000>星期五的晚上，一帮同事在希格玛大厦附近的&#8220;硬盘酒吧&#8221;多喝了几杯。程序员多喝了几杯之后谈什么呢？自然是算法问题。有个同事说：</font></p>
<p><font color=#800000>&#8220;我以前在餐馆打工，顾客经常点非常多的烙饼。店里的饼大小不一，我习惯在到达顾客饭桌前，把一摞饼按照大小次序摆好——小的在上面，大的在下面。由于我一只手托着盘子，只好用另一只手，一次抓住最上面的几块饼，把它们上下颠倒个个儿，反复几次之后，这摞烙饼就排好序了。</font>
<p><font color=#800000>我后来想，这实际上是个有趣的排序问题：假设有<em>n</em>块大小不一的烙饼，那最少要翻几次，才能达到最后大小有序的结果呢？</font>
<p><font color=#800000>你能否写出一个程序，对于<em>n</em>块大小不一的烙饼，输出最优化的翻饼过程呢？</font></p>
<p>排序问题是数据结构和算法中比较重要的一个了，之前在<a href="http://www.cppblog.com/Fox/archive/2008/03/20/unwisdom_or_impavidity.html" target=_blank>一篇被同事成为标题党的文章</a>中因为提到排序中关于（非）稳定排序的概念还被很多TX鄙视了一番，甚至引来人身攻击，现在想来都有些后怕。</p>
<p>这道题目一眼看上去最先让我想到的居然是那道经典的<a href="http://en.wikipedia.org/wiki/Tower_of_Hanoi" target=_blank>汉诺塔（Tower of Hanoi）</a>问题（当然，<a href="http://en.wikipedia.org/wiki/Tower_of_Hanoi" target=_blank>汉诺塔</a>不算排序问题）。</p>
<p><font color=#800000>1) 相似点★：</font></p>
<p>a. 都要不断调整位置，最终实现从小到大排好；</p>
<p>b. 都要借助中间量进行调整。</p>
<p><font color=#800000>2) 不同处★：</font></p>
<p>a. 汉诺塔有多出来的两根针，翻烙饼只有一只手，明确说明没有第三只手；</p>
<p>b. 汉诺塔一次只能移动一个，翻烙饼没限制；</p>
<p>c. 汉诺塔要保证小的始终在上面，翻烙饼没限制；</p>
<p>d. 汉诺塔移动之前就有序，所以其移动次数是固定的，算法的逻辑也固定（不管是递归还是栈操作），翻烙饼没有这个前提。</p>
<p><font color=#800000>3) 把题目用程序语言描述一下吧★：</font></p>
<p>a. Input : <em>n</em>.</p>
<p>b. Process : generate <em>n</em> random number 0-(n-1), sortting.</p>
<p>c. Output : 0, 1, ..., n-1, and move times <em>num</em>.</p>
<p><font color=#800000>4) 存储结构★★★：</font></p>
<p>我最开始想到的是：这一摞烙饼其实就是一个双链表，每翻一次相当于将头节点H与某非头节点N进行如下变换：</p>
<p>H-&gt;next = N-&gt;next</p>
<p>N-&gt;prior = H-&gt;prior = NULL</p>
<p>N-&gt;next-&gt;prior = H</p>
<p>如果使用普通的双链表，这儿就有一个很明显的问题，H和N之间的所有节点（如果有的话）的<font color=#800000>前趋prior和后继next互换</font>了，对于<em>n</em>比较大的情况，这个操作明显浪费时间啊（<font color=#800000>交换前趋prior和后继next和题目要求的翻几次似乎也没有关系吧</font>？只是我作为一个一线的Coder考虑的太具体了）。如果摒弃前趋和后继的概念，又该怎样描述呢？</p>
<p><a href="http://www.ctworld.org/chan_master/east010.htm" target=_blank>唐朝禅宗大师青原行思</a>曾说：<font color=#800000><strong>参禅之初，看山是山，看水是水；禅有悟时，看山不是山，看水不是水；禅中彻悟，看山仍然山，看水仍然是水</strong></font>。</p>
<p>俗：日，扯那么多，什么意思？
<p>师：前趋不是前趋，后继不是后继。
<p>俗：日，前趋不是前趋，难道是后继吗？
<p>师：然也。
<p><font color=#800000><strong>Fox：O, my God！整点实际的吧！翻转一次之后，前趋视为后继，后继视为前趋，第奇数次翻转的前趋是后继，第偶数次翻转的后继是前趋。</strong></font>
<p>整个链表的形态如下：</p>
<p>H:Head, F:First, G:F's next, B:C's prior, C:Change, D, C's next, L:Last.</p>
<p>H&lt;==&gt;F&lt;==&gt;G&lt;=...=&gt;B&lt;==&gt;C&lt;==&gt;D&lt;=...=&gt;L</p>
<p>F与C交换的操作如下（Word、PS画图），n表示next，p表示prior：</p>
<p align=center><img src="http://lh3.ggpht.com/yulefox/SAnuzSRgEtI/AAAAAAAAAMg/EFmsyGW5lWw/s800/flapjack_before_cross.jpg"> </p>
<p align=center><img src="http://lh3.ggpht.com/yulefox/SAnuySRgEsI/AAAAAAAAAMY/ncke8G_JIXo/s800/flapjack_after_cross.jpg%22" src_cetemp='http://lh3.ggpht.com/yulefox/SAnuySRgEsI/AAAAAAAAAMY/ncke8G_JIXo/s800/flapjack_after_cross.jpg"'> </p>
<p>这里只需要修改<font color=#800000>F、D节点的prior，H、C节点的next</font>，其他节点不变。</p>
<p>后面想了一下，这种方式很难在不添加flag或者对换n、p的情况下正常操作，没有找到好的方法<span style="FONT-FAMILY: wingdings">L</span>，<font color=#800000><strong>如果你有好的方法不妨告诉我</strong></font>。</p>
<p>最后只好作罢，何苦呢？直接使用数组就完了嘛<span style="FONT-FAMILY: wingdings">J</span>！既然是数组，除了翻转移动麻烦一点，理解和操作还是很容易的。</p>
<p>果然不是搞数学、算法出身的，一上来考虑的就是如何存储^.^''''，而不是算法本身。</p>
<p><strong><font color=#800000>更可笑的是，扯了半天，最后居然还是用数组</font></strong>！</p>
<p><font color=#800000>5) 算法分析★★★★★：</font></p>
<p><strong><font color=#800000>冒泡排序思想：</font></strong></p>
<p>最关键的是要抽象出<strong>随机数列特征</strong>（含当前和移动后数列特征的抽象），并尽量使每一次翻转<strong>有效</strong>（所谓<strong>有效</strong>，即尽量保证每一次操作都向最后的有序靠近而非背离 ）。</p>
<p>师：要使大头在后，应使大头在后。</p>
<p>俗：日，这是什么狗屁逻辑？</p>
<p>师：因果。在前既是在后。</p>
<p>俗：USA, CNN（操你娘）。</p>
<p>师：翻转。既不在前，也不在后，使之在前，使之在后。</p>
<p>俗：日，什么东西？既不在前，也不在后，不前不后，难道在中间啊？</p>
<p>师：然也。</p>
<p><strong><font color=#800000>Fox：O, my God！整点实际的吧！整个过程分为n轮，在第i(i=0, 1, ..., n-1)轮：</font></strong></p>
<p>a. 找到大头<em><strong>n-i</strong></em>，是否有序？是，转g；</p>
<p>b. 是否大头在后？是，转f；</p>
<p>c. 是否大头在前？是，转e；</p>
<p>d. 将队头（第一个元素）与大头<strong><em>n-i</em></strong>对调（别忘了是翻转，中间元素也变序了），++<strong><em>times</em></strong>；</p>
<p>e. 将队头<strong><em>n-i</em></strong>与第n-i个元素对调，++<strong><em>times</em></strong>；</p>
<p>f. ++<strong><em>i</em></strong>，转a；</p>
<p>g. 输出序列（0, 1, ..., n）和翻转次数<strong><em>times</em></strong>；OVER:D。</p>
<p><strong><font color=#800000>快速排序思想：</font></strong></p>
<p>在最开始的时候，我就想到使用快速排序的思想，先使整个数列局部有序，最后调整使全部有序。<strong><font color=#800000>悲哀的是，在我考虑 4 3 1 2这个数列的时候，我断定还要通过上面的方式重新像冒泡排序一样重新来过，立即放弃想法，于是给了上面的思路，而且坚定的认为这个方法已经很好</font></strong>。结果，下午GR告诉我他的反例：<font color=#800000><strong>4 3 1 2 --&gt; 2 1 3 4|--&gt; 1 2| 3 4</strong></font>，&#8220;|&#8221;表示从该处翻转。</p>
<p>我必须承认，这才是好的方法，我过分拘泥于不去改动已经有序的部分。然而，这家伙只知道反驳我，却无法给出算法。</p>
<p>我只好自己重新考虑局部有序之后的问题。</p>
<p>十分钟后，我有了如下的答案（<strong><font color=#800000>目前我能想到的最佳答案</font></strong>），但不得不承认，<strong><font color=#800000>表述算法比给出一种情况对应的解要麻烦的多的多的多</font></strong>，假定A、B满足<strong><font color=#800000>A==B-1</font></strong>，即A、B为相邻数列（为简单记，元素和数列统称数列）。则A、B的组合类型有8种：<strong>B(O)A(O)、B(C)A(O)、B(O)A(C)、B(C)A(C)、A(C)B(O)、A(O)B(O)、A(C)B(C)、A(O)B(C)</strong>，O表示正向（obverse）C表示逆向（reverse），以1 2 3 4为例：</p>
<p><font color=#800000><font color=#000000><strike>B(O)A(O)：3 4 1 2&lt;2&gt;</strike>、</font>B(C)A(O)：4 3 1 2&lt;4&gt;<font color=#000000>、</font><strong>B(O)A(C)：3 4 2 1</strong>&lt;5&gt;</font>、B(C)A(C)：4 3 2 1&lt;7&gt;；</p>
<p><font color=#800000><font color=#000000><strike>A(C)B(C)：2 1 4 3&lt;1&gt;</strike>、</font>A</font><font color=#800000>(O)B(C)：1 2 4 3&lt;3&gt;<font color=#000000>、</font><strong>A(C)B(O)：2 1 3 4</strong>&lt;6&gt;</font><font color=#000000>、A(O)B(O)：1 2 3 4&lt;8&gt;。</font></p>
<p>对应操作规则如下：</p>
<p><strike>a. 0x0101: B(O)A(O) --&gt; B(C)A(O)； 3</strike></p>
<p>b. 0x0001: B(C)A(O) --&gt; A(C)B(O)； 2</p>
<p><font color=#800000>c. 0x0101: B(O)A(C) --&gt; <strong>B(C)A(C)</strong>；1</font></p>
<p>d. 0x0000: B(C)A(C)：<strong>如果当前只剩A、B两个子列</strong>，则翻转一次成<strong><font color=#800000>A(O)B(O)1 2 3 4为最终结果</font></strong>，否则，认为<strong><font color=#800000>B(C)A(C)</font></strong>可以<strong>作为一个逆序有序数列考虑</strong>，暂时无需翻转；</p>
<p><strike>e. 0x1010: A(C)B(C) --&gt; A(O)B(C)； 3</strike></p>
<p>f. 0x1110: A(O)B(C) --&gt; B(O)A(C)；&nbsp; 2</p>
<p><font color=#800000>g. 0x1011: A(C)B(O) --&gt; <strong>A(O)B(O)</strong>；1</font></p>
<p>h. 0x1111: A(O)B(O)：A、B可以<strong>作为一个有序数列考虑</strong>，<strong>如果当前只有A、B两个子列</strong>，则正序序列<strong><font color=#800000>A(O)B(O)1 2 3 4为最终结果</font></strong>。</p>
<p>上面规则的制定其实是<strong>反向导出</strong>的，遵循的原则是，正序有序的<strong><font color=#800000>A(O)B(O)</font></strong>和逆序有序的<strong><font color=#800000>B(C)A(C)</font></strong>可以看作一个序列，A(C)B(O)、B(O)A(C)可一步达到，B(C)A(O)、A(O)B(C)可两步达到，B(O)A(O)、A(C)B(C)可三步达到。即对于4个元素，<strong>最坏的的A(C)B(C)需要4步</strong>（对应于上面的<font color=#800000>冒泡法却只需要3步</font><span style="FONT-FAMILY: wingdings">L</span>）。而且当元素比较多的时候，记住1、2个有序子列是可行的，但对于完全无序的数列，分析出所有有序子列，既不现实，也无必要。</p>
<p>修改规则如下：<font color=#800000>当<strong>队头无序</strong>&amp;&amp;<strong>相邻数列有序</strong>||<strong>队头有序</strong>，翻转队头；否则，将队头连同该元素一同翻转</font>。</p>
<p>由此可见，这算法还要改进：</p>
<p>a. 判断<strong><em>Array</em>[0]</strong>是否正序连续（连续个数<strong><em>nNum1</em></strong>），如果<em><strong>nNum1</strong></em>==<strong><em>n</em></strong>，转i，如果<strong><em>nNum1</em></strong>!=1，转c；</p>
<p>b. 判断<strong><em>Array</em>[0]</strong>是否逆序连续（连续个数<strong><em>nNum1</em></strong>），如果<em><strong>nNum1</strong></em>==<strong><em>n</em></strong>，翻转<strong><em>Array</em></strong>，转f；</p>
<p>c. 从下标<strong><em>nNum1</em></strong>开始查找<strong><em>Array</em>[0]</strong>+1（<em><strong>bObserve</strong></em> = true）和<strong><em>Array</em>[0]-</strong>1（<em><strong>bObserve</strong></em> = false）的下标<strong><em>nStart2</em></strong>，如果<strong><em>nNum1</em></strong>==<strong><em>nStart2</em></strong>，<strong><em>bOrder1</em></strong>==true，转e，如果<strong><em>nNum1</em></strong>!=1，置<strong><em>nEnd2</em></strong>=<strong><em>nStart2</em></strong>；</p>
<p>d. 判断( <em><strong>bObserve</strong></em> == true&amp;&amp;<strong><em>Array</em>[nStart2]</strong>+1<strong>==<em>Array</em>[nStart2+1] </strong>) || ( <em><strong>bObserve</strong></em> == false&amp;&amp;<strong><em>Array</em>[nStart2]==<em>Array</em>[nStart2+1]</strong>+1 )，true则置<strong><em>nEnd2</em></strong>=<strong><em>nStart2</em></strong>，false则置<strong><em>nEnd2</em></strong>=<strong><em>nStart2</em></strong>+1；</p>
<p>e. 翻转<strong>Array[0]</strong> to <strong>Array[nEnd2]</strong>，转a；</p>
<p>f. 输出<strong>Array</strong>及<strong>times</strong>。</p>
<p>这样来看，改进后的算法竟<strong>简单</strong>了许多！</p>
<p>不幸的是：按上面给出的算法翻转合并1 3 5 6 4 8 7 9 2 0：</p>
<p><font color=#800000>1 3 5 6 4 8 7 9| </font><font color=#008000>2|</font> 0</p>
<p><font color=#800000>2 9 7 8 4 6 5|</font> <font color=#008000>3|</font> 1 0</p>
<p><font color=#800000>3 5 6|</font> <font color=#008000>4|</font> 8 7 9 2 1 0</p>
<p><font color=#800000>4 6|</font> <font color=#008000>5|</font> 3 8 7 9 2 1 0</p>
<p><font color=#800000><strong>5 6</strong>|</font> 4 3 8 7 9 2 1 0</p>
<p><font color=#800000>6 5 4 3 8|</font> <font color=#008000>7|</font> 9 2 1 0</p>
<p><font color=#800000>7 8 3 4 5|</font> <font color=#008000>6|</font> 9 2 1 0</p>
<p>进入死循环了&#8230;&#8230;</p>
<p>很明显应该是下面这个样子：</p>
<p><font color=#800000>1 3 5 6 4 8 7 9 2|</font> 0</p>
<p><font color=#800000>9 8 7 4 6 5|</font> 3 1 2 0</p>
<p><font color=#800000>5 6 4|</font> 7 8 9 3 1 2 0</p>
<p><font color=#800000>6 5 4 7|</font> 8 9 3 1 2 0</p>
<p><font color=#800000>4 5 6 7 8 9 3|</font> 1 2 0</p>
<p><font color=#800000>3 4 5 6 7 8 9 1 2|</font> 0</p>
<p><font color=#800000>1 9 8 7 6 5 4 3 2|</font> 0</p>
<p><font color=#800000>2 3 4 5 6 7 8 9 1|</font> 0</p>
<p><font color=#800000>9 8 7 6 5 4 3 2 1 0|</font></p>
<p><font color=#008000><strong>0 1 2 3 4 5 6 7 8 9</strong></font></p>
<p>执行9次翻转。算法如何得到呢？</p>
<p>a. 确定最小无序完整子集<strong><em>Sn</em></strong>（<strong><em>Sn</em></strong>中含<strong><em>n</em></strong>&gt;1个连续数）；</p>
<p>b. 将<strong><em>Sn</em></strong>最前面的有序子集<strong><em>So</em></strong>（<strong><em>o</em></strong>&gt;1）加以考虑，一个子集？两个子集？</p>
<p>______________________________________________________________________________</p>
<p><strong><font color=#800000>O, my God!</font></strong></p>
<p>这个问题，从前天晚上到现在，思考、分析、抽象了至少有15个小时以上了：</p>
<p>a. Apr.18th-19th: 23:00 - 01:30</p>
<p>b. Apr.19th: 11:00 - 13:00</p>
<p>c. Apr.19th-20th: 22:00 - 05:30</p>
<p>d. Apr.20th: 11:00 - 15:00</p>
<p>结果是，到现在无法给出一个最优的翻转算法。一个周末都花在这上面了，<strong><font color=#800000>准备放弃</font></strong><span style="FONT-FAMILY: wingdings">L</span>。</p>
<p><a href="http://pekingone.blog.sohu.com/" target=_blank>LP</a>催着我让我回学校，是该回去了！</p><img src ="http://www.cppblog.com/Fox/aggbug/47659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-20 14:59 <a href="http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何产生随机数</title><link>http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 15 Apr 2008 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47118.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47118.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47118.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>
				<a href="http://en.wikipedia.org/wiki/John_von_Neumann" target="_blank">John von Neumann</a>说：<font color="#800000">Any one who considers arithmetical methods of producing random digits is , of course, in a state of sin.</font></p>
		<p>所以，在讨论算法实现随机数的时候，总是说“<font color="#800000">伪随机数</font>”。</p>
		<p>现在，应用最广的随机数生成算法是由<a href="http://en.wikipedia.org/wiki/Derrick_Henry_Lehmer" target="_blank">Derrick Henry Lehmer</a>1951年给出的<a href="http://en.wikipedia.org/wiki/Linear_congruential_generator" target="_blank">线性同余法</a>：</p>
		<p>              Xn+1 = ( aXn + c ) mod m,  n&gt;=0.</p>
		<p>在<a href="/Fox/archive/2008/04/03/mmorpg_security_prng.html" target="_blank">上一篇伪随机数的论述</a>中，并没有给出X0, a, c, m的取值规则，只是给出了<a href="http://en.wikipedia.org/wiki/ANSI_C" target="_blank">ANSI C</a>和<a href="http://en.wikipedia.org/wiki/Visual_C%2B%2B" target="_blank">Microsoft Visual C++</a>的实现。</p>
		<p>在这儿我们可以自己先思考一下，我们期望从上式中得到的随机数应该满足：</p>
		<p>
		</p>
		<p>1) 上式的输出足够随机，这是最基本的要求；</p>
		<p>2) 上式给出尽量多的输出，越接近m个越好（不可能超过m），即周期尽量长，最好为m，这样才能保证上式满足<font color="#800000">均匀分布</font>（<strike>m个数在周期m中各出现一次</strike>m个数出现的概率相等）；</p>
		<p>3) 上式的生成速度足够快。</p>
		<p>最容易想到的，<font color="#800000">m的取值为计算机字大小（如2^32或2^64）</font>。</p>
		<p>但是这儿有个很严重的问题：<font color="#800000">Xn低位的随机性很弱</font>。原因如下：</p>
		<p>令d|m, 且</p>
		<p>              Yn = Xn mod d</p>
		<p>则</p>
		<p>              Yn+1 = ( ( aXn + c ) mod m ) mod d</p>
		<p>                      = ( aYn + c ) mod d</p>
		<p>上述表达式的意义即：Yn为Xn低k位（d=2^k），这样的<font color="#800000">Yn序列形成周期为d甚至更短的同余序列</font>。举例说明：d为2^1时，Yn为Xn的最低位（可假定为1或0），若Yn+1 != Yn，则Yn+2 == Yn必定成立，仅当a、c皆为奇数时Yn、Yn+1将0、1交替，否则，为常数（0或1）。</p>
		<p>暂时抛开随机性不管，先找到周期为m的随机序列中的取值规则。</p>
		<p>
				<a href="http://en.wikipedia.org/wiki/Donald_Knuth">Donald Knuth</a>在<i>The Art of Computer Programming</i>, Volume 2: <em>Seminumerical Algorithms</em>中的<em>3.2.1.2</em>节对m, a, c和X0取值规则的表述：</p>
		<p>1) gcd(c, m) = 1. 即<font color="#800000">c, m互素</font>，再白一点，c, m除1之外没有其他公因子；</p>
		<p>2) 任给质数p, p|m ==&gt; p|(a-1). 即m%p==0，则(a-1)%p==0。</p>
		<p>3) 4|m ==&gt; 4|(a-1). 即m%4==0，则(a-1)%4==0。</p>
		<p>这个证明过程对于我这样的<font color="#800000"><a href="http://en.wikipedia.org/wiki/Number_theory" target="_blank">数论</a>基础</font>不是很扎实的搞应用技术的人来说有点难以理解了。有兴趣的话，还是去看<em>3.2.1.2</em>的证明吧:-)。</p>
		<p>上面的规则告诉我们，满足了上述规则后，可以保证序列周期为m。对于前面提到的关于随机性的问题，既然Xn低位的随机性比较弱，可以只取<font color="#800000">Xn的高位</font>作为输出。高位的<font color="#800000">随机性和统计意义</font>由a, c确定，其取值涉及<font color="#800000">统计检验</font>，具体的也还是看<em>3.3</em>吧。</p>
		<p>这篇文章解决了<font color="#800000">具有统计意义的随机数</font>的部分理论问题。</p>
		<p>PS: <a href="/Fox/archive/2008/03/06/mmorpg_net_iocp.html" target="_blank">之前曾经BS过Windows Live Writer</a>，当时觉得Writer编辑功能太少，<span style="COLOR: #800000">不能直接设定链接文字的字体颜色</span>，知道CSS可以设定之后，又觉得Word 2007编辑的Blog转成html之后太大，而且也知道Word 2007上面是可以设置链接的target为_blank的。现在发现Writer还是很不错的了，原来是<font color="#800000">可以设定格式</font>的，也可以直接编辑html，而且可以Web预览，链接还可以加入到<font color="#800000">链接词汇表</font>，挺方便的。</p>
		<p>越来越发现<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>是个和<a href="http://www.google.com/" target="_blank">Google</a>一样的好东西！</p><img src ="http://www.cppblog.com/Fox/aggbug/47118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-15 14:01 <a href="http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络游戏安全思考——伪随机数篇</title><link>http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 02 Apr 2008 18:35:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/46126.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/46126.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/46126.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>一、随机数</p>
		<p>软件实现的<span style="COLOR: #800000">随机数生成器(random number generator, RNG)</span>生成的随机数列大多是<span style="COLOR: #800000">惟定数列</span>，因此一般被称作<span style="COLOR: #800000">伪随机数(pseudorandom number, PRN)</span>，而基于<span style="COLOR: #800000">热噪声(thermal noise)</span>、<span style="COLOR: #800000">光电效应(photoelectric effect)</span>、<span style="COLOR: #800000">放射性衰变(radioactive disintegration)</span>等不可预知的物理现象实现的<span style="COLOR: #800000">硬件随机数生成器(hardware random number generator)</span>生成的随机数才被认为是<span style="COLOR: #800000">真随机数(truly random number)</span>。PRN在计算机领域主要用于<span style="COLOR: #800000">仿真(simulation)和密码学(cryptography)。</span></p>
		<p>本文仅讨论伪随机数软件实现算法，并且仅讨论满足<span style="COLOR: #800000">均匀分布(uniform distribution, UD)</span>的伪随机数发生器(pseudorandom number generator, PRNG)。<span style="COLOR: #800000">非均匀分布(non-uniform distribution, NUD)</span>的PRNG可通过满足均匀分布的PRNG与非线性函数生成。</p>
		<p>本文讨论的PRNG应满足以下三点：</p>
		<p>a. 在取值空间内满足<span style="COLOR: #800000">UD</span>，即等概率取得取值空间内任意值。</p>
		<p>b. <span style="COLOR: #800000">充分随机</span>，即该随机数列周期(period)应尽量长。此点由所谓的<span style="COLOR: #800000">熵(entropy)</span>度量。</p>
		<p>c. <span style="COLOR: #800000">唯一输入或称种子(seed)对应唯一输出PRN</span>。这一点ms是计算机的强项，也是PRN惟定的根源，也是算法被破解的根源。</p>
		<p>由于PRN sequence(PRNS)惟定，所以算法的安全性主要取决于<span style="COLOR: #800000">熵的选择和算法的复杂性</span>。</p>
		<p>二、可预测PRNG与不可预测PRNG</p>
		<p>所谓<span style="COLOR: #800000">可预测(determined)PRNG</span>，也被称为统计意义上的PRNG(statistic PRNG)，一般只有一个seed，而对于同一个seed，生成的PRNS是惟定的。</p>
		<p>不可<span style="COLOR: #800000">预测(indetermined)PRNG</span>，从理论上讲，不可预测的PRNG是不存在的，这儿指密码学安全的PRNG(cryptographically secure PRNG, CSPRNG)。</p>
		<p>三、常用PRNGs</p>
		<p>1、<span style="COLOR: #800000">线性同余发生器(linear congruential generators, LCG)</span></p>
		<p>
				<a href="http://www.dawuwei.com/shanbowei/" target="_blank">单博伟</a>在<a href="http://www.dawuwei.com/shanbowei/post/250.html" target="_blank">标准库rand()函数的缺陷以及Blitz++随机数生成的简介</a>中给出了The C Programming Langurage 2nd的实现，我手头没有这本书，所以无从查证，<a href="http://fallhunter.spaces.live.com/" target="_blank">FallHunter</a>应该还有吧。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">unsigned </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> next </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">1</span>
				<span style="COLOR: #000000">;<br /></span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_29_80_Open_Image" onclick="this.style.display='none'; Codehighlighter1_29_80_Open_Text.style.display='none'; Codehighlighter1_29_80_Closed_Image.style.display='inline'; Codehighlighter1_29_80_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_29_80_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_29_80_Closed_Text.style.display='none'; Codehighlighter1_29_80_Open_Image.style.display='inline'; Codehighlighter1_29_80_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_29_80_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
				<span id="Codehighlighter1_29_80_Open_Text">
						<span style="COLOR: #008000">/*</span>
						<span style="COLOR: #008000"> rand: return pseudo-random integer on 0..32767 </span>
						<span style="COLOR: #008000">*/</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> rand(</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">)<br /></span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_97_178_Open_Image" onclick="this.style.display='none'; Codehighlighter1_97_178_Open_Text.style.display='none'; Codehighlighter1_97_178_Closed_Image.style.display='inline'; Codehighlighter1_97_178_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_97_178_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_97_178_Closed_Text.style.display='none'; Codehighlighter1_97_178_Open_Image.style.display='inline'; Codehighlighter1_97_178_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_97_178_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_97_178_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 6</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /> next </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> next </span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">1103515245</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">+</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">12345</span>
						<span style="COLOR: #000000">;<br /></span>
						<span style="COLOR: #008080"> 7</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> (unsigned </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000">)(next</span>
						<span style="COLOR: #000000">/</span>
						<span style="COLOR: #000000">65536</span>
						<span style="COLOR: #000000">) </span>
						<span style="COLOR: #000000">%</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">32768</span>
						<span style="COLOR: #000000">;<br /></span>
						<span style="COLOR: #008080"> 8</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 9</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_181_212_Open_Image" onclick="this.style.display='none'; Codehighlighter1_181_212_Open_Text.style.display='none'; Codehighlighter1_181_212_Closed_Image.style.display='inline'; Codehighlighter1_181_212_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_181_212_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_181_212_Closed_Text.style.display='none'; Codehighlighter1_181_212_Open_Image.style.display='inline'; Codehighlighter1_181_212_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_181_212_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
				<span id="Codehighlighter1_181_212_Open_Text">
						<span style="COLOR: #008000">/*</span>
						<span style="COLOR: #008000"> srand: set seed for rand() </span>
						<span style="COLOR: #008000">*/</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> srand(unsigned </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> seed)<br /></span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_244_260_Open_Image" onclick="this.style.display='none'; Codehighlighter1_244_260_Open_Text.style.display='none'; Codehighlighter1_244_260_Closed_Image.style.display='inline'; Codehighlighter1_244_260_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_244_260_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_244_260_Closed_Text.style.display='none'; Codehighlighter1_244_260_Open_Image.style.display='inline'; Codehighlighter1_244_260_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_244_260_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_244_260_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">13</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /> next </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> seed;<br /></span>
						<span style="COLOR: #008080">14</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>VS2003中给的实现是：</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img id="Codehighlighter1_0_258_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_258_Open_Text.style.display='none'; Codehighlighter1_0_258_Closed_Image.style.display='inline'; Codehighlighter1_0_258_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_0_258_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_258_Closed_Text.style.display='none'; Codehighlighter1_0_258_Open_Image.style.display='inline'; Codehighlighter1_0_258_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span id="Codehighlighter1_0_258_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
				<span id="Codehighlighter1_0_258_Open_Text">
						<span style="COLOR: #008000">/*</span>
						<span style="COLOR: #008000">**<br /></span>
						<span style="COLOR: #008080"> 2</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*rand.c - random number generator<br /></span>
						<span style="COLOR: #008080"> 3</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080"> 4</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       Copyright (c) Microsoft Corporation. All rights reserved.<br /></span>
						<span style="COLOR: #008080"> 5</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080"> 6</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Purpose:<br /></span>
						<span style="COLOR: #008080"> 7</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       defines rand(), srand() - random number generator<br /></span>
						<span style="COLOR: #008080"> 8</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080"> 9</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />******************************************************************************</span>
						<span style="COLOR: #008000">*/</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">cruntime.h</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">mtdll.h</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">stddef.h</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">stdlib.h</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">15</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">16</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#ifndef _MT<br /></span>
				<span style="COLOR: #008080">17</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">static</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">long</span>
				<span style="COLOR: #000000"> holdrand </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">1L</span>
				<span style="COLOR: #000000">;<br /></span>
				<span style="COLOR: #008080">18</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">#endif</span>
				<span style="COLOR: #000000">  /* _MT */</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">19</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">20</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_401_778_Open_Image" onclick="this.style.display='none'; Codehighlighter1_401_778_Open_Text.style.display='none'; Codehighlighter1_401_778_Closed_Image.style.display='inline'; Codehighlighter1_401_778_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_401_778_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_401_778_Closed_Text.style.display='none'; Codehighlighter1_401_778_Open_Image.style.display='inline'; Codehighlighter1_401_778_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_401_778_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
				<span id="Codehighlighter1_401_778_Open_Text">
						<span style="COLOR: #008000">/*</span>
						<span style="COLOR: #008000">**<br /></span>
						<span style="COLOR: #008080">21</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*void srand(seed) - seed the random number generator<br /></span>
						<span style="COLOR: #008080">22</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">23</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Purpose:<br /></span>
						<span style="COLOR: #008080">24</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       Seeds the random number generator with the int given.  Adapted from the<br /></span>
						<span style="COLOR: #008080">25</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       BASIC random number generator.<br /></span>
						<span style="COLOR: #008080">26</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">27</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Entry:<br /></span>
						<span style="COLOR: #008080">28</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       unsigned seed - seed to seed rand # generator with<br /></span>
						<span style="COLOR: #008080">29</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">30</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Exit:<br /></span>
						<span style="COLOR: #008080">31</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       None.<br /></span>
						<span style="COLOR: #008080">32</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">33</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Exceptions:<br /></span>
						<span style="COLOR: #008080">34</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">35</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />******************************************************************************</span>
						<span style="COLOR: #008000">*/</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">36</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">37</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> __cdecl srand (<br /></span>
				<span style="COLOR: #008080">38</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        unsigned </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> seed<br /></span>
				<span style="COLOR: #008080">39</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        )<br /></span>
				<span style="COLOR: #008080">40</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_838_971_Open_Image" onclick="this.style.display='none'; Codehighlighter1_838_971_Open_Text.style.display='none'; Codehighlighter1_838_971_Closed_Image.style.display='inline'; Codehighlighter1_838_971_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_838_971_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_838_971_Closed_Text.style.display='none'; Codehighlighter1_838_971_Open_Image.style.display='inline'; Codehighlighter1_838_971_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_838_971_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_838_971_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">41</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />#ifdef _MT<br /></span>
						<span style="COLOR: #008080">42</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">43</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        _getptd()</span>
						<span style="COLOR: #000000">-&gt;</span>
						<span style="COLOR: #000000">_holdrand </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> (unsigned </span>
						<span style="COLOR: #0000ff">long</span>
						<span style="COLOR: #000000">)seed;<br /></span>
						<span style="COLOR: #008080">44</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">45</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">#else</span>
						<span style="COLOR: #000000">  /* _MT */</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">46</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        holdrand </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">long</span>
						<span style="COLOR: #000000">)seed;<br /></span>
						<span style="COLOR: #008080">47</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">#endif</span>
						<span style="COLOR: #000000">  /* _MT */</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">48</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">49</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">50</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">51</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_975_1271_Open_Image" onclick="this.style.display='none'; Codehighlighter1_975_1271_Open_Text.style.display='none'; Codehighlighter1_975_1271_Closed_Image.style.display='inline'; Codehighlighter1_975_1271_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_975_1271_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_975_1271_Closed_Text.style.display='none'; Codehighlighter1_975_1271_Open_Image.style.display='inline'; Codehighlighter1_975_1271_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_975_1271_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
				<span id="Codehighlighter1_975_1271_Open_Text">
						<span style="COLOR: #008000">/*</span>
						<span style="COLOR: #008000">**<br /></span>
						<span style="COLOR: #008080">52</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*int rand() - returns a random number<br /></span>
						<span style="COLOR: #008080">53</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">54</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Purpose:<br /></span>
						<span style="COLOR: #008080">55</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       returns a pseudo-random number 0 through 32767.<br /></span>
						<span style="COLOR: #008080">56</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">57</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Entry:<br /></span>
						<span style="COLOR: #008080">58</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       None.<br /></span>
						<span style="COLOR: #008080">59</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">60</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Exit:<br /></span>
						<span style="COLOR: #008080">61</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*       Returns a pseudo-random number 0 through 32767.<br /></span>
						<span style="COLOR: #008080">62</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">63</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*Exceptions:<br /></span>
						<span style="COLOR: #008080">64</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />*<br /></span>
						<span style="COLOR: #008080">65</span>
						<span style="COLOR: #008000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />******************************************************************************</span>
						<span style="COLOR: #008000">*/</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">66</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">67</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> __cdecl rand (<br /></span>
				<span style="COLOR: #008080">68</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">69</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        )<br /></span>
				<span style="COLOR: #008080">70</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_1316_1582_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1316_1582_Open_Text.style.display='none'; Codehighlighter1_1316_1582_Closed_Image.style.display='inline'; Codehighlighter1_1316_1582_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_1316_1582_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1316_1582_Closed_Text.style.display='none'; Codehighlighter1_1316_1582_Open_Image.style.display='inline'; Codehighlighter1_1316_1582_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_1316_1582_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_1316_1582_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">71</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />#ifdef _MT<br /></span>
						<span style="COLOR: #008080">72</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">73</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        _ptiddata ptd </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> _getptd();<br /></span>
						<span style="COLOR: #008080">74</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">75</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000">( ((ptd</span>
						<span style="COLOR: #000000">-&gt;</span>
						<span style="COLOR: #000000">_holdrand </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> ptd</span>
						<span style="COLOR: #000000">-&gt;</span>
						<span style="COLOR: #000000">_holdrand </span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">214013L</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">76</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span>
						<span style="COLOR: #000000">+</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">2531011L</span>
						<span style="COLOR: #000000">) </span>
						<span style="COLOR: #000000">&gt;&gt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">16</span>
						<span style="COLOR: #000000">) </span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0x7fff</span>
						<span style="COLOR: #000000"> );<br /></span>
						<span style="COLOR: #008080">77</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">78</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">#else</span>
						<span style="COLOR: #000000">  /* _MT */</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">79</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000">(((holdrand </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> holdrand </span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">214013L</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">+</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">2531011L</span>
						<span style="COLOR: #000000">) </span>
						<span style="COLOR: #000000">&gt;&gt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">16</span>
						<span style="COLOR: #000000">) </span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0x7fff</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">80</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #0000ff">#endif</span>
						<span style="COLOR: #000000">  /* _MT */</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">81</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>
				<br />2、<span style="COLOR: #800000">LFG, LFSR等</span></p>
		<p>限于篇幅，有兴趣的TX可以参考后面的资料，主要是<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>，上面给的算法还是非常详细的，CSPRNGs包括<span style="COLOR: #800000">Blum Blum Shub、Fortuna</span>等。</p>
		<p>如果出于安全性的考虑，PRNG的输出不应直接作为种子。在《<span style="COLOR: #800000">构建安全的软件</span>》一书中，作者认为“<span style="COLOR: #800000">一个好的PRNG具有这样的性质：给足够的熵，即使攻击者知道全部的算法细节，还是不能猜出生成的数据流</span>”。</p>
		<p>三、PRNG的安全测试</p>
		<p>
				<span style="COLOR: #800000">FIPS-140</span>标准包含了对RNs的测试规范。这个标准我也没有去仔细看，所以没法给出更多的信息。被提到的测试包有<span style="COLOR: #800000">DIEHARD、pLab</span>。</p>
		<p>四、随机数在游戏中的应用</p>
		<p>1、<span style="COLOR: #800000">随机数为游戏带来更多的不确定性，不确定性产生可玩性</span></p>
		<p>这个应该是所有游戏的根本了吧。游戏中玩家、怪物、NPC的很多属性都是一个范围，比如攻击就有最小攻击和最大攻击，每次的实际攻击伤害总在二者之间。</p>
		<p>同样的，玩家乐此不疲的一次次“洗装备”、“碰运气”。其他类推吧。</p>
		<p>2、<span style="COLOR: #800000">游戏的AI更多的依赖于随机数</span></p>
		<p>如果怪物、NPC的AI一切尽在玩家的掌握中，游戏的乐趣就大大降低了，这一点在单机游戏中有着很好的体现。War3中，人机对战，电脑的战术并不单一（但还是有规律可循，人类玩家尚且如此），这其中固然有多方面 的因素。但随机数的功劳也不容抹杀。</p>
		<p>3、<span style="COLOR: #800000">随机数减少数据存储，一个种子可以代替一批数据</span></p>
		<p>游戏中含有大量数据，如果每一项都要存取，对时间和空间都是一个考验。对于场景中随机生成的怪物信息，如果给定一个相同的种子。呃，是不是要简单一些呢？</p>
		<p>五、相关内容</p>
		<p>至于为什么PRNGs大多使用素数，需要更多的<span style="COLOR: #800000">数论知识</span>，对密码学有了解的TX应该能够体会到<span style="COLOR: #800000">安全和数论</span>之间的紧密联系。因为手头没有数论的书，所以不多加妄测了。到时写论文的时候，再填充上吧。</p>
		<p>六、参考文献</p>
		<p>1. 构建安全的软件. [美]John Viega, Gary McGraw. 钟向群, 王鹏 译.  北京. 清华大学出版社, 2003.</p>
		<p>2. Pseudorandom number generator及相关链接. <a href="http://en.wikipedia.org/wiki/Pseudorandom_number_generator" target="_blank">http://en.wikipedia.org/wiki/Pseudorandom_number_generator</a></p>
		<p>3. PRNG - Pseudo-Random Number Generator. <a href="http://statmath.wu-wien.ac.at/prng/" target="_blank">http://statmath.wu-wien.ac.at/prng/</a></p>
		<p>-------------------------------------------------------------------------</p>
		<p>PS01：手上的几本书</p>
		<p>从几位TX那儿拿的几本书，放在桌上大半年了，一直没有怎么翻过。想想周末还给他们算了，于是就拿过来翻翻，立此存照，如果以后用到的话，再来查。</p>
		<p>a. 《<span style="COLOR: #800000">用TCP/IP进行网际互联</span>》Vol. III，主要是针对Linux/POSIX套接字的C/S架构实现。因为MMORPG的C/S架构多依赖于TCP，上面第8、10-16章的内容可以关注一下。</p>
		<p>b. 《<span style="COLOR: #800000">构建安全的软件</span>》，上面关于开源、闭源的口水(Chap. 4)，关于缓冲区溢出(Chap. 7)，关于随机数(Chap. 10)，关于数据库安全(Chap. 14)，关于客户端安全(Chap. 15)，都是值得一看的东西。</p>
		<p>c. 《<span style="COLOR: #800000">UNIX环境高级编程</span>》，进程控制(Chap. 8)、线程控制(Chap. 12)、进程通信(Chap. 15, 17)、套接字(Chap. 16)、数据库(Chap. 20)。</p>
		<p>d. 《<span style="COLOR: #800000">UNIX网络编程</span>》Vol.I，如果涉及到泛UNIX操作系统下网络编程，可以当作参考书翻。</p>
		<p>e. 《<span style="COLOR: #800000">计算机安全原理</span>》，加密(Chap. 5)、认证(Chap. 6)、协议安全(Chap. 7)、入侵检测(Chap. 13)、恶意攻击(Chap. 15)、灾难恢复(Chap. 19)。</p>
		<p>PS02：<a href="http://feeds.feedburner.com/~r/Techcrunch/~3/261961535/" target="_blank">微软宣布不会抬高收购Yahoo价格</a></p>
		<p>消息来自<a href="http://online.wsj.com/article/SB120701820580579519.html?mod=googlenews_wsj" target="_blank">Wall Street Journal</a>，不过当天可是<span style="COLOR: #800000">April Fool</span>。</p>
		<p>PS03：关于<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a></p>
		<p>不是说<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>被禁的吗？很久没有访问过了，这么好的东西，被封了还是很遗憾的。</p>
		<p>PS04：有问题</p>
		<p>发现问题，找<a href="http://www.google.com/" target="_blank">Google</a>；解决问题，找<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>。</p>
		<p>PS05：欢迎补充</p>
		<p>-------------------------------------------------------------------------</p>
		<p>Added on Apr.10th</p>
		<p>今天从<a href="http://www.codeproject.com/">CodeProject</a>上看到一篇文章<a href="http://www.codeproject.com/KB/cpp/PRNG.aspx">Applied Crypto++: Pseudo Random Number Generators</a>)，作者<font color="#a52a2a">Jeffrey Walton</font>对密码学和安全比较有研究。</p>
		<p>Jeffrey Walton对Knuth的<a href="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming">The Art of Computer Programming Vol.2</a>中关于随机数的部分作了概括。</p>
		<p>这篇文章从一个<font color="#a52a2a">工程师的角度</font>给出了随机数的应用和实现，很具有参考性。</p>
		<p>作者还从<a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf">FIPS 140-2</a>标准中引用了下面一段话：</p>
		<p>Random Number Generators fall into one of two classes: deterministic and nondeterministic. A deterministic RNG consists of an algorithm that produces a sequence of bits from an initial value called a seed. A nondeterministic RNG produces output that is dependent on some unpredictable physical source that is outside human control. </p>
		<p>这一段话很好的说明，<font color="#a52a2a">依赖于算法的RNG所生成的随机数列只可能是伪随机数，真随机数依赖于不可预测的物理源</font>。</p><img src ="http://www.cppblog.com/Fox/aggbug/46126.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-03 02:35 <a href="http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MMORPG网络模型剖析——网络连接实例分析</title><link>http://www.cppblog.com/Fox/archive/2008/03/28/mmorpg_network_impl_analysis.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Thu, 27 Mar 2008 17:41:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/03/28/mmorpg_network_impl_analysis.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/45569.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/03/28/mmorpg_network_impl_analysis.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/45569.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/45569.html</trackback:ping><description><![CDATA[<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">Author: Fox </span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<span style="COLOR: black">在以前写</span>
						<a href="/Fox/archive/2007/12/16/game_world_architecture.html" target="_blank">MMORPG中游戏世界的构建</a>
						<span style="COLOR: black">时，提到服务器架构的分类。大多数情况下，每一种不同的服务器只会与其对应的一个服务器和多个客户端通信。比如，GameServer(GS)只会与WorldServer(WS)通信，也就是说GS只作为WS的客户端。这次，由于项目需求，新增加了一个SomeServer(SS)作为GS的服务器。 </span>
				</span>
		</p>
		<p>
				<span style="COLOR: #c00000; FONT-FAMILY: 宋体">一、SS网络连接分析 </span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<span style="COLOR: black">由于需要和大量GS建立网络连接，所以SS使用了IOCP模型。鉴于</span>
						<a href="/Fox/archive/2008/03/06/mmorpg_net_iocp.html" target="_blank">上一次写IOCP</a>
						<span style="COLOR: black">时遭到</span>
						<a href="/kevinlynx/" target="_blank">Kevin</a>
						<span style="COLOR: black">TX的鄙视，所以决定今天多写一点。SS的网络模型大致如下： </span>
				</span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">0、服务器主线程启动； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">1、初始化Winsock，SDK func: WSAStartup ()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">2、创建一个使用overlapped I/O的socket，SDK func: WSASocket()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">3、绑定端口，将本地地址与创建的socket关联起来，SDK func: bind()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">4、创建IOCP对象，SDK func: CreateIoCompletionPort()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">5、创建工作者线程，CreateWorkerThreads()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">6、开始监听，SDK func: listen()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">7、接受客户端连接，SDK func: WSAAccept()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">8、当有新的连接请求到达时，将WSAAccept返回的对应的客户端socket关联到IOCP； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">9、处理WSASend() or WSARecv()。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">在实际处理时，可能会根据需要建立额外的线程处理socketopt命令，甚至建立专门处理WSAccept的线程。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">关于工作者线程WorkerThread： </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">通过GetQueuedCompletionStatus()，获取I/O类型和对应的socket，如果为接收则通知接收完成并继续新的WSARecv()，如果为发送则通知发送完成。 </span>
		</p>
		<p>
				<span style="COLOR: #c00000; FONT-FAMILY: 宋体">二、GS网络连接分析 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">GS上对于SS客户端采用的是WSAEventSelect模型，通过网络事件触发相应操作。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">0、服务器主线程启动； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">1、初始化Winsock，SDK func: WSAStartup ()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">2、创建一个使用overlapped I/O的socket，SDK func: WSASocket()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">4、绑定端口，将本地地址与创建的socket关联起来，SDK func: bind()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">5、创建网络事件，SDK func: CreateEvent()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">6、设置网络事件的响应，SDK func: WSAEventSelect()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">7、等待网络事件，SDK func: WSAWaitForMultipleEvents()； </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">8、分析网络事件类型并处理，SDK func: WSAEnumNetworkEvents()。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">这里之所以采用CreateEvent而不是WSACreateEvent，是因为由CreateEvent创建的事件允许为auto reset的，而WSACreateEvent创建的事件是manually reset的。 </span>
		</p>
		<p>
				<span style="COLOR: #c00000; FONT-FAMILY: 宋体">三、实现过程中的小插曲 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">在GS的客户端实现中遇到几个问题。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">首先是在消息处理上，GS发到SS的消息，SS并没有完全接受到，而SS发送到GS的消息一切正常。后来跟了一下SS消息队列，发现SS居然可以收到GS发送到WS的消息！然后就在GS上找原因，原来是WS在和SS共用消息队列，以前GS只对应一个服务器，无所谓共用。现在加了SS，自然要分开处理，否则WS和SS都可能收到发给对方的消息。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">后面一个bug从周一开始已经强奸了我四天了。即使SS已经关闭，WSAEnumNetworkEvents返回的事件对应FD_CONNECT的iErrorCode值始终为0。因为中间涉及到多线程和多个服务器分别对应的客户端，连接到WS的没有问题，就是SS的客户端有问题。到今天上午为止，我已经把GS的网络处理逻辑全部静态分析了一遍，没有任何发现。临近中午吃饭的时候，不得已只好用WS的客户端socket去连接SS，居然出现同样问题！而我的WS和SS都是放在我机器上的，这样来看，就只有端口不同了！ </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">果然，当我把SS的监听端口修改之后，问题解决了。因为我是使用8088端口监听GS连接的。当我把端口换成80，同样问题再次出现，而且SS无法通过80端口监听。 </span>
		</p>
		<p>
				<span style="COLOR: black; FONT-FAMILY: 宋体">接下来提几个问题： </span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<span style="COLOR: black">1、</span>
						<span style="COLOR: #c00000">被卡巴斯基监控的端口8088和服务器开启的监听端口8088有什么联系？为什么没有冲突？卡巴仅仅只是从该端口获取数据吗？为什么网络事件的FD_CONNECT的对应iErrorCode为0（表明连接成功）？</span>
						<span style="COLOR: black">
						</span>
				</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<span style="COLOR: black">2、</span>
						<span style="COLOR: #c00000">80是常规http端口，它与8080、8088这些http端口的区别在哪儿？这些端口绑定成功与否的原则是什么？</span>
						<span style="COLOR: black">
						</span>
				</span>
		</p>
		<p> </p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<span style="COLOR: black">PS：文中关于IOCP和WSAEventSelect模型更为详细的实现，可以参考</span>
						<a href="http://www.amazon.com/Network-Programming-Microsoft-Windows-Second/dp/0735615799" target="_blank">Network Programming for Microsoft Windows 2<sup>nd</sup></a>
						<span style="COLOR: black">的第五章：Winsock I/O Methods。</span>
				</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">最后写完了，发觉自己写的很垃圾，完全就是记流水帐。转念一想，为什么呢？自己基础不扎实嘛，第一次接触IOCP和网络模型，也就这样了。 </span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">今天太晚了，要睡了，上面的问题明天再考虑吧</span>
				<span style="FONT-FAMILY: Wingdings">J</span>
				<span style="FONT-FAMILY: 宋体">。</span>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/45569.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-03-28 01:41 <a href="http://www.cppblog.com/Fox/archive/2008/03/28/mmorpg_network_impl_analysis.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>不怕无知，但怕无畏</title><link>http://www.cppblog.com/Fox/archive/2008/03/20/unwisdom_or_impavidity.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Thu, 20 Mar 2008 13:17:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/03/20/unwisdom_or_impavidity.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/44970.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/03/20/unwisdom_or_impavidity.html#Feedback</comments><slash:comments>48</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/44970.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/44970.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>昨天越俎代庖面试了一个家伙。 </p>
		<p>看完了他的笔试题目，感觉后背有点凉，但这些东西看看也就过去了，说实话，那些C++的题目多少<span style="COLOR: #c00000">有点BT</span>。 </p>
		<p>但我一直觉得DS的东西，如果你当初学的时候是很认真学习过并思考过的，其实是不需要去记忆的，所以我就问了一个关于<span style="COLOR: #c00000">稳定排序和不稳定排序</span>的问题。我想，只要你理解了各种排序算法的思想，很easy。 </p>
		<p>只是这哥们儿忘记了什么是稳定排序，我还以为他把快速排序、堆排序当作稳定排序只是没记住。看来，老师从小教育的"<span style="COLOR: #c00000">一道题目你即使不会也要尽量去答</span>"这种思想遗毒颇深。如果抱着这种思想做程序员，公司多半要垮掉。 </p>
		<p>想一想稳定排序的概念吧：两个同值元素（不知为什么，我一直记得<a href="http://www.amazon.cn/mn/detailApp?ref=DT_TS&amp;uid=000-0000000-0000000&amp;prodid=zjbk002885" target="_blank">严老师书上</a>用的是49，看来我还是在<span style="COLOR: #c00000">读死书</span>、<span style="COLOR: #c00000">死读书</span>，最后可能会<span style="COLOR: #c00000">读书死</span><span style="FONT-FAMILY: Wingdings">L</span>）在排序前后相对位置保持不变，即本来在前面的还在前面（所谓"<span style="COLOR: #c00000">尘归尘，土归土</span>"，看来最近思想有点消极，难怪没有激情<span style="FONT-FAMILY: Wingdings">L</span>）。再想想各种排序的思想，我们很容易得到这样的结论：最普通的O(n<sup>2</sup>)的算法，一个一个从前比到后，自然不会影响到同值元素的相对位置，而O(nlogn)的算法，由于多路比较，可能导致本来相对位于后面的元素先比较和移动，造成不稳定。这样一想，自然知道简单的插入、选择、归并排序都是稳定的，而改进的高效率的算法则不稳定。 </p>
		<p>后面另一个同事在询问他做的Demo的事情，因为是DX的东西，我不懂，没插嘴，就随便看他的简历。 </p>
		<p>看到其中一项，有提到他曾经给大一、大二的学生做过C++培训。我本没打算提他笔试中的C++部分的，但既然曾经为人师表（因为我曾经做过学生、也做过老师），C++基础掌握到这种程度就不对了。尤其对于一个空的C++类默认生成哪些成员函数居然写的一塌糊涂（<span style="COLOR: #c00000">友情提示：你也不用BS他，如果你没有看过Lippman的《</span><a href="http://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545" target="_blank">Inside of the C++ Object Model</a><span style="COLOR: #c00000">》，建议你先不要发言<span style="FONT-FAMILY: Wingdings">J</span></span>）。 </p>
		<p>我一般对语言特性不太敢发表观点（因为我的C++基础不扎实<span style="FONT-FAMILY: Wingdings">L</span>），但我对简单的算法或思想小有兴趣（没有你想象中那么高）。可是，笔试中唯一的一个需要coding的题目他又没写。我只好说，C++的东西你掌握怎么样我也可以不看，但这个memcpy的实现，你怎么也得有点想法吧？不然怎么去写代码呢？刚好在面他之前，还和同事讨论过memcpy的问题（如果你给出<span style="COLOR: #c00000">one byte by one byte</span>的实现会遭BS的<span style="FONT-FAMILY: Wingdings">J</span>，因为你居然没有考虑过计算机系统本身的数据处理）。 </p>
		<p>本来还想问他一个关于<a href="/qiujian5628/archive/2008/02/29/43477.html" target="_blank">sizeof()的问题</a>，后来觉得也没什么必要，关于<span style="COLOR: #c00000"><span style="FONT-FAMILY: Verdana">union</span><span style="FONT-FAMILY: 宋体">的对齐，要按照单位最长的成员对齐</span></span><span style="FONT-FAMILY: 宋体">这一点自己都觉得有点</span>BT就算了。 </p>
		<p>其实，我想说的是，很多东西，你不能认为你掌握的很好（除非你真的掌握的很好），所谓很好，拿C++来说，就是把你认为你好的地方，你可以不翻其他东西，把它写下来，基本跟ISO C++保持90%以上的相似度就可以了。当然，这样说有点贱了。 </p>
		<p>毕竟，做游戏程序员（其他也差不多吧）需要的是： </p>
		<p>
				<span style="COLOR: #c00000">带着激情去编码，带着虚心去学习，带着挑战去交流，带着压力去工作。 </span>
		</p>
		<p>激情，能让你的思维满具创意，代码极其飘逸； </p>
		<p>虚心，能让你的知识不断积累，从而达到厚积薄发； </p>
		<p>挑战，能让你的团队充满活力，交流活泼严谨； </p>
		<p>压力，能让你的心态保持平衡，胜不妄喜，败不惶馁。<span style="TEXT-DECORATION: underline"></span></p>
		<p>因为自己这两周心态受到<span style="COLOR: #c00000">非智力因素</span>干扰，日子过得有点<span style="COLOR: #c00000">浑噩</span>。写下来，主要是为了放松一下，也提醒自己。 </p>
		<p>
				<span style="COLOR: #c00000">不怕无知，但怕无畏。</span>
				<br />
				<br />-----------------------------------------------------------------<br /><br />PS：补记于2008/03/26<br /><br />还是把上午写的一个mymemcpy放上来吧。里面没有对des &lt; src + len的重叠情况进行讨论，因为大致google了一下，似乎很少人这样做（倒不是因为不能实现）。</p>
		<p>void *mymemcpy( void *src, void *des, size_t len )<br />{<br /> char *tempsrc = (char *)src;<br /> char *tempdes = (char *)des;</p>
		<p> size_t offset = len / 4;<br /> for( size_t i=0; i&lt;offset; ++i )<br /> {<br />  *(unsigned long *)tempdes = *(unsigned long *)tempsrc;<br />  tempdes += sizeof(unsigned long);<br />  tempsrc += sizeof(unsigned long);<br /> }<br /> <br /> offset = len - len % 4;<br /> for( size_t i=0; i&lt;offset; ++i )<br /> {<br />  *tempdes++ = *tempsrc++;<br /> }<br /> return des;<br />}</p>
		<p>刚才想求证一下memcpy在地址重叠的情况下，是否会考虑从后往前copy的情况。结果看到<a href="http://blog.codingnow.com/2005/10/vc_memcpy.html" target="_blank">云风的blog上很早的一篇文章</a>，也是讲memcpy的，角度不同。</p>
		<p>我想澄清一点，我写这篇blog的初衷只是总结几个技术问题，因此就没有把面试的前因后果讲一下，反倒让很多朋友误解，以为我怎么怎么样了。</p>
		<p>事实情况是，这几个问题都是本来的笔试题目当中的，面试的TX从上午10:00前后做到11:30过，等我和另一个同事13点过去的时候，我一直没怎么说话。只是在一边看他的简历和题目，文中已经说了，是看到他的简历之后才提的问题。当时是有10道左右的C++题目，他做对的其实只有一道。</p>
		<p>而且，我在提问题的时候也都将问题跟他一起分析了的（除了memcpy之外），自我感觉说话还是很得体的，写文章的风格是另一码事儿。</p>
		<p>我没有丝毫瞧不起这位TX的意思，也完全没有显摆的想法。</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 10pt">
				<span lang="EN-US">
						<font face="Calibri">PS</font>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">：忽然想到自己最近为什么<span style="COLOR: #c00000">癖性十足</span>，因为最近在关注<span style="COLOR: #c00000">一个家伙的</span></span>
				<span lang="EN-US" style="COLOR: #c00000">
						<font face="Calibri">Blog</font>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">，如果不侵权，我想用用他的</span>
				<span lang="EN-US">
						<font face="Calibri">Blog</font>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的名字《</span>
				<a href="http://www.wangxiaofeng.net/">不许联想</a>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">》，作者是<span style="COLOR: #c00000">带三个表</span>的<span style="COLOR: #c00000">王小峰</span>（《三联生活周刊》记者）。所以，如果有人想拍我，建议先看看他的东西，<span style="COLOR: #c00000">学习一下措辞</span></span>
				<span lang="EN-US" style="COLOR: #c00000; FONT-FAMILY: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings">
						<span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings">J</span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">。一个同事，说天涯也行，我个人觉得天涯有点相互吹捧的味道。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 10pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">恶心，但没有恶意</span>
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings">
						<span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings">J</span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">。</span>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/44970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-03-20 21:17 <a href="http://www.cppblog.com/Fox/archive/2008/03/20/unwisdom_or_impavidity.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MMORPG网络模型剖析——IOCP篇</title><link>http://www.cppblog.com/Fox/archive/2008/03/06/mmorpg_net_iocp.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 05 Mar 2008 17:18:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/03/06/mmorpg_net_iocp.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/43783.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/03/06/mmorpg_net_iocp.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/43783.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/43783.html</trackback:ping><description><![CDATA[<p>
				<span style="FONT-FAMILY: Verdana">Author: Fox </span>
		</p>
		<p>
				<span style="COLOR: green; FONT-FAMILY: Verdana">//-----------------------------------------------------------------------------------------------------<br /></span>
				<span style="COLOR: darkgreen">夜深了，随便写写……<span style="FONT-FAMILY: Verdana"><br /></span></span>
				<span style="COLOR: green; FONT-FAMILY: Verdana">//-----------------------------------------------------------------------------------------------------</span>
		</p>
		<p>大凡学过编程语言和网络的TX应该都写过自己的聊天程序，那时候大家都知道了套接字怎么<span style="FONT-SIZE: 10pt"><span style="FONT-FAMILY: Arial">select</span><span style="FONT-FAMILY: 宋体">、</span><span style="FONT-FAMILY: Arial">connect</span><span style="FONT-FAMILY: 宋体">、</span><span style="FONT-FAMILY: Arial">bind</span><span style="FONT-FAMILY: 宋体">、</span><span style="FONT-FAMILY: Arial">listen</span><span style="FONT-FAMILY: 宋体">、</span><span style="FONT-FAMILY: Arial">accept</span><span style="FONT-FAMILY: 宋体">、</span><span style="FONT-FAMILY: Arial">send</span><span style="FONT-FAMILY: 宋体">、</span><span style="FONT-FAMILY: Arial">recv</span><span style="FONT-FAMILY: 宋体">，也知道了</span><span style="FONT-FAMILY: Arial">TCP</span><span style="FONT-FAMILY: 宋体">和</span><span style="FONT-FAMILY: Arial">UDP</span></span><span style="FONT-FAMILY: 宋体"><span style="FONT-SIZE: 10pt">的区别</span>……稍微用功的</span>TX或许还写过多人聊天程序，知道了什么是阻塞I/O，真正致力于向QQ、MSN等即时聊天工具靠齐的大牛对本文提到的IOCP更是了然于胸。更多的TX或者有兴趣继续看下去。 </p>
		<p>一、阻塞I/O（主要指TCP） </p>
		<p>1、当socket的recv buff为空时，进程会wait直到新数据到达； </p>
		<p>2、当socket的send buff已满时，进程会wait直到空间足够； </p>
		<p>3、当socket的accept没有新连接到达，进程会wait直到新连接到达； </p>
		<p>4、当socket的connect没有收到ACK，进程会wait直到收到ACK。 </p>
		<p>而非阻塞I/O则是致力于提供高效的异步I/O。 </p>
		<p>二、IOCP（<span style="FONT-SIZE: 10pt"><span style="FONT-FAMILY: Arial">I/O Completion Port</span><span style="FONT-FAMILY: 宋体">，</span><span style="FONT-FAMILY: Arial">I/O</span></span><span style="FONT-FAMILY: 宋体"><span style="FONT-SIZE: 10pt">完成端口</span>）</span></p>
		<p>IOCP是MS提供的Windows内核对象，内部使用线程池管理，并根据CPU的个数确定线程个数。当数据到达后，统一投递到唯一的IOCP队列，对应的若干工作线程用于处理这些数据，从而实现非阻塞异步I/O。 </p>
		<p>简单了解了IOCP的功能和原理，下面提供几点线索，供有兴趣的TX整理思绪<span style="FONT-FAMILY: Wingdings">J</span>。 </p>
		<p>1、OVERLAPPED结构： </p>
		<p>2、CreateIoCompletioPort：用于创建IOCP，关联连接来的socket句柄，用于接收数据； </p>
		<p>3、GetQueuedCompletionStatus：供工作线程调用，取到数据的线程会加入I/O完成队列，IOCP的线程池管理这些工作线程。 </p>
		<p>三、深入学习和使用 </p>
		<p>1、Jeffrey Richter的<a href="http://www.amazon.com/Advanced-Windows-Jeffrey-Richter/dp/1572315482" target="_blank">《Advanced Windows》</a>，第15章，谁看谁知道<span style="FONT-FAMILY: Wingdings">J</span>； </p>
		<p>2、Jim Beveridge &amp; Robert Wiener的<a href="http://www.amazon.com/Multithreading-Applications-Win32-Addison-Wesley-Technology/dp/0201442345" target="_blank">《Multithreading Applications in Win32》</a>，第6章，谁看谁知道<span style="FONT-FAMILY: Wingdings">J</span>； </p>
		<p>3、<a href="http://www.google.cn/" target="_blank">Google</a>。 </p>
		<p>
				<span style="COLOR: green; FONT-FAMILY: Verdana">//-----------------------------------------------------------------------------------------------------<br /></span>
				<span style="COLOR: darkgreen">感觉用Office 2007编辑和发布Blog比Live Writer要方便很多，主要是Live Writer的编辑功能太少了，如果2007能够对链接进行target设置，<br />再支持EntryName就perfact了<span style="FONT-FAMILY: Wingdings">J</span>。<br /><span style="FONT-FAMILY: 宋体">从新公司回来，还没有完全适应这边宽松的环境，这几天好似梦游一般，先是</span><span style="FONT-FAMILY: Verdana">IE</span><span style="FONT-FAMILY: 宋体">出问题，</span><span style="FONT-FAMILY: Verdana">Ghost</span><span style="FONT-FAMILY: 宋体">了一道，后面是</span><span style="FONT-FAMILY: Verdana">Outlook</span><span style="FONT-FAMILY: 宋体">收邮件出问题。</span><span style="FONT-FAMILY: Verdana"><br /></span><span style="FONT-FAMILY: 宋体">还是夜深人静的时候，一个人燃着烟、听着歌、喝着茶、敲着键盘有感觉……</span><span style="FONT-FAMILY: Verdana"><br /></span></span>
				<span style="COLOR: green; FONT-FAMILY: Verdana">//-----------------------------------------------------------------------------------------------------</span>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/43783.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-03-06 01:18 <a href="http://www.cppblog.com/Fox/archive/2008/03/06/mmorpg_net_iocp.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络游戏安全思考——IPSec篇</title><link>http://www.cppblog.com/Fox/archive/2008/02/28/game_security_ipsec.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Thu, 28 Feb 2008 12:54:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/02/28/game_security_ipsec.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/43411.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/02/28/game_security_ipsec.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/43411.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/43411.html</trackback:ping><description><![CDATA[<p>Author: Fox </p>
		<p>
				<span style="COLOR: green">//-----------------------------------------------------------------------------------------------------<br />关于反外挂，这两天在和几位同事和网友讨论的结果依然是，更多的要从策划角度解决……<br />//----------------------------------------------------------------------------------------------------- </span>
		</p>
		<p>最近在考虑安全问题的时候，在《游戏编程精粹3》中看到Pete Isensee的《安全套接字》（即通常所说的Secure Socket Layer, SSL技术），又Google了一些IPSec的相关资料。尽管IPSec是部署在IP层的协议，但它还是可以为我们提供一些思路。 </p>
		<p>一、IPSec的认证安全（AH+ESP） </p>
		<p>1、不可否认性：采用公钥加密的数字签名具有抗抵赖性。 </p>
		<p>2、防止报文重放：使用序列号和滑动窗口以保证数据包的唯一性，即使数据包被截获重发，也会因序列号的相同或者错误而被抛弃。 </p>
		<p>3、完整性：IPSec使用单独的鉴别头部（Authentication Header, AH）信息进行校验，防止报文篡改，校验的算法主要是MD5、SHA-1等单向哈希算法。 </p>
		<p>4、可靠性：通过加密封装安全有效载荷（Encapsulating Security Payload, ESP），IPSec对传输数据进行保护，加密算法除了MD5、SHA-1，还有加密块链接（Cipher Block Chaining, CBC）模式加密算法等。 </p>
		<p>二、IPSec的数据加密 </p>
		<p>在数据加密上，IPSec使用的主要是DES（Data Encryption Standard）和3DES（Triple Data Encryption Standard）算法。 </p>
		<p>三、IPSec的密钥管理 </p>
		<p>为了保证数据传输安全，IPSec使用由IKE（Internet Key Exchange）提供的动态密钥更新机制，Diffie-Hellman算法提供密钥生成策略，通信两端需要维持一个安全关联（Security Association），为两端通信指定认证及加密所用算法和密钥，并提供序列号和滑动窗口等。 </p>
		<p>需要注意的是，IPSec并没有提供数据产生到发送之前的保护机制。举例来说，就是IPSec可以在最大程度上保证你输入的帐号密码在传输过程中的安全，但并不能防止钓鱼软件和其他木马在你输入这些信息时被截获<span style="FONT-FAMILY: Wingdings">L</span>，那应该是你要注意的。 </p>
		<p>对IPSec有兴趣的TX可以到<a href="http://www.ietf.org">http://www.ietf.org</a>上下载相关的RFC文档研究研究<span style="FONT-SIZE: 9pt; FONT-FAMILY: Wingdings">J</span>。 </p>
		<p>
				<span style="COLOR: green">//-----------------------------------------------------------------------------------------------------<br />本以为手上工作完成，可以偷时间看看安全方面的东西，不曾想Joe又分下了新任务<span style="FONT-FAMILY: Wingdings">L</span>……<br />//-----------------------------------------------------------------------------------------------------</span>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/43411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-02-28 20:54 <a href="http://www.cppblog.com/Fox/archive/2008/02/28/game_security_ipsec.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络游戏安全思考——反外挂篇</title><link>http://www.cppblog.com/Fox/archive/2008/02/26/game_security_anti_cheat.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 26 Feb 2008 08:04:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/02/26/game_security_anti_cheat.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/43266.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/02/26/game_security_anti_cheat.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/43266.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/43266.html</trackback:ping><description><![CDATA[<p>Author: Fox </p>
		<p>
				<span style="COLOR: green">//-----------------------------------------------------------------------------------------------------<br />此篇仅是对反脱机外挂的一点思考，其他安全问题如登录验证、消息验证等更多的是涉及逻辑功能。<br />//----------------------------------------------------------------------------------------------------- </span>
		</p>
		<p>春节刚回来的时候，回公司去和Soft聊到了自己的毕业论文的问题，因为专业的关系，我必须给出一些安全方面的考虑，正是因为这一点，我当时开题时就立足对安全的无缝游戏世界进行思考。只是在游戏本身的安全性上，一直也没有一个好的出发点，这两周还是在考虑这个问题。 </p>
		<p>这一点，有我入行时间不长，对于游戏本身、玩家与开发者（含游戏及外挂、木马开发者）之间的关系并没有一个很好的把握，更多的是由于我对游戏中的可用的安全技术不了解，尤其是对应用层安全协议不了解，对破解技术也不了解，导致无所适从。 </p>
		<p>《游戏编程精粹1》中Andrew Kirmse在《在线游戏的网络协议》一文中对常见的篡改报文、报文重放和逆向工程有讲述。预防报文篡改的有效防御是哈希校验，现在大多游戏是使用MD5算法，而且网上开源的MD5代码也很多。对于报文重放，Andrew提到了使用线性叠加随机数的状态机，具体原理和实现方式因为没有提到太详细，还要针对实际应用继续学习<span style="FONT-FAMILY: Wingdings">L</span>。然而，由于客户端既是报文的接收者也是发送者，因此，客户端包括了完整的加解密算法。一旦客户端被逆向，上述措施就变成了破解者背后的烟雾弹，完全失去意义。 </p>
		<p>提到反外挂，Joe的看法也是说这个东西和具体某一个技术关系不大，还是要从机制上去看。加不加密对于普通玩家没有意义，对于专业从事逆向的人更是也没有意义，所有单纯考虑加密是没有效果的。对于免费游戏，外挂往往是打钱公司的工具，你封他的号，他再建就是了，代价几乎为0，而一般付费游戏（像魔兽世界）一个帐号对应一个CDKey，一个CDKey就要几十块钱，这个封起来就有点咬牙了。 </p>
		<p>说到这里，不妨换个思路：为免费游戏加入CDKey。我一款游戏从内测、封测到公测，让玩家充分参与体验，在被逆向且外挂横行之前，按正常逻辑运营。进而假定我这一款游戏在公测之后，让玩家感觉魅力十足。引导玩家并实施CDKey，一个CDKey大约会需要玩家付出些许Money以示诚意，在玩家游戏过程中，会阶段性向玩家赠送部分增值道具。老玩家在进入新区时，需要申请继续使用原CDKey。这样一来，外挂就不会肆无忌惮了。 </p>
		<p>BTW，这个思路没有从技术角度解决问题，下面再来看一种略微关乎技术实现的解决方案：动态验证。在游戏运行期间，会<span style="COLOR: red">不定期的向玩家发送验证码</span>，客户端在收到消息后，必须<span style="COLOR: red">在一定时间内响应</span>，向服务器确认收到的验证码，否则将被<span style="COLOR: red">强制下线</span>，再次登录后将<span style="COLOR: red">更加频繁的收到验证码</span>，直到用其良好的回复次数累积<span style="COLOR: red">消除其不良记录</span>为止。为了尽量减少因此给玩家造成的不友好体验，在任务场景、重要PK场景或者高等级玩家活动场景，验证码的发送和确认可<span style="COLOR: red">适当放宽</span>。 </p>
		<p>当然，如果外挂中加入了图形识别，这一招也未必奏效。 </p>
		<p>不知是道高还是魔高，可以肯定的一点是：大家都是在利益的驱动下绞尽脑汁。 </p>
		<p>
				<span style="COLOR: green">//-----------------------------------------------------------------------------------------------------<br />春节回来之后，一直比较忙（确切的说是比较懒），没有更新，宜更加勤奋。<br />最近工作涉及到数据库编程，一点点对数据库的读写居然耗掉我3天时间，汗！<br />//-----------------------------------------------------------------------------------------------------</span>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/43266.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-02-26 16:04 <a href="http://www.cppblog.com/Fox/archive/2008/02/26/game_security_anti_cheat.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>异步回调的一种封装——续</title><link>http://www.cppblog.com/Fox/archive/2008/01/25/asny_callback_ex.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Fri, 25 Jan 2008 03:27:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/01/25/asny_callback_ex.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/41873.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/01/25/asny_callback_ex.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/41873.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/41873.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>终于赶在周末之前调通了，现在来总结一下我这个项目中对于异步回调的应用背景。</p>
		<p>这个项目的内容就是在游戏中使用第三方库为所有玩家提供更好的服务，当server启动后，加载dll，初始化该模块，当server退出时，结束模块功能，卸载dll。</p>
		<p>当玩家提出请求后，server在main thread中通过lib转发玩家请求，lib处理完毕，在其独立thread中回调server为其实现的callback function。此时，server需要将返回的result转到main thread中对result及其相关的玩家数据进行处理。</p>
		<p>第三方库的需求是很明确的，在合适的地方发送请求，在合适的地方处理响应。</p>
		<p>Joe对我的要求也是很明确的，响应处理时采用server当前架构(这个架构在<a href="/Fox/archive/2008/01/23/asny_callback.html" target="_blank">上一篇文中</a>有提到)，使我的编码不涉及任何游戏功能逻辑处理，并使整个处理流程细节对后续应用开发透明。</p>
		<p>二者结合起来，就为这个项目融入整个server的架构提供了完美的需求，也为我的编码提供了最小限度的选择空间:(，好处是后续功能开发可以完全无视我的编码，只需实现对回调响应后的功能，只有server底层知悉如何调用。</p>
		<p>给出序列图：</p>
		<p> </p>
		<p align="center">
				<img alt="uml_asny_callback" src="http://www.cppblog.com/images/cppblog_com/Fox/6064/r_uml_asny_callback.jpg" align="center" />
		</p>
		<p>为了保持对上层开发透明，OnCallback需要封装。</p>
		<p>
				<font color="#006400">//-------------------------------------------------------------------------------<br />// 一年来，我主要参与了两款游戏，确切的说是半年，前面半年并没有真正涉及运营产品的开发，只是做工具。<br />// 现在这个模块是我做的最快，也是压力最大的一个。现在想来，原因在于此模块涉及到游戏主逻辑底层和<br />// 第三方动态链接库的通信及处理。<br />// 在短短几天的时间内让你的设计满足第三方库的应用需求并符合游戏自身底层逻辑的设计风格，的确有些痛苦，<br />// 好在有Joe的指点，让我在完成工作的同时又学到了一些方法:)。<br />//-------------------------------------------------------------------------------</font>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/41873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-01-25 11:27 <a href="http://www.cppblog.com/Fox/archive/2008/01/25/asny_callback_ex.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>异步回调的一种封装</title><link>http://www.cppblog.com/Fox/archive/2008/01/23/asny_callback.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 23 Jan 2008 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/01/23/asny_callback.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/41699.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/01/23/asny_callback.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/41699.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/41699.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>前段时间写过一篇<a href="/Fox/archive/2008/01/10/multithread_security.html/" target="_blank">关于线程安全</a>的文字，有TX觉得不深入。因为本来就没想写的太具体，只是随便说说，今天就想说点具体的技术。</p>
		<p>
				<font color="#006400">//-------------------------------------------------------------------------------<br />// 动态链接库 (Dynamic Link Library)</font>
		</p>
		<p>1) 动态链接；</p>
		<p>2) 跨语言；</p>
		<p>3) Win32平台可用；</p>
		<p>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080"> 1</span> <span style="COLOR: #008000">//</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008000"> 静态链接库.h文件中对函数的声明：<br /></span>
								<span style="COLOR: #008080"> 2</span> <span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> dllExam.h</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080"> 3</span> <span style="COLOR: #008000"></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">__stdcall</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"> Func( </span><span style="COLOR: #0000ff">int</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000"> nParam );<br /></span>
								<span style="COLOR: #008080"> 4</span>  </font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008000"> 动态链接库.h文件中对函数的声明：<br /></span>
								<span style="COLOR: #008080"> 6</span> <span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> dllExam.h</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080"> 7</span> <span style="COLOR: #008000"></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> __declspec( dllexport ) </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">__stdcall</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"> Func( </span><span style="COLOR: #0000ff">int</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000"> nParam );<br /></span>
								<span style="COLOR: #008080"> 8</span>  </font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 动态链接库的静态调用：</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">10</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">#pragma comment(lib,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">dllExam.lib</span><span style="COLOR: #000000">"</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">) <br /></span>
								<span style="COLOR: #008080">11</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> __declspec(dllimport) </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">__stdcall</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"> Func( </span><span style="COLOR: #0000ff">int</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000"> nParam );<br /></span>
								<span style="COLOR: #008080">12</span>  </font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">13</span> <span style="COLOR: #000000">dllFun(</span><span style="COLOR: #000000">0</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">14</span>  </font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">15</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008000"> 动态链接库的动态调用：<br /></span>
								<span style="COLOR: #008080">16</span> <span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> useDllExam.cpp</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">17</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">typedef </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">(</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">__stdcall</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">CallFun )( </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> );    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 宏定义，方便使用</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">18</span> <span style="COLOR: #008000"></span></font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">19</span> <span style="COLOR: #000000">HINSTANCE hDll;                        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> DLL句柄</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">20</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">CallFun dllFun;                        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 库函数指针</span></font>
				</font>
				<span style="COLOR: #008000">
						<br />
				</span>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #008080">21</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">hDll </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> LoadLibrary( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">dllExam.dll</span><span style="COLOR: #000000">"</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000"> );<br /></span>
								<span style="COLOR: #008080">22</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">if</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">( hDll )<br /></span>
								<span style="COLOR: #008080">23</span>  </font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">{<br /></span>
								<span style="COLOR: #008080">24</span> <span style="COLOR: #000000">    dllFun </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (CallFun)GetProcAddress(hDll, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Func</span><span style="COLOR: #000000">"</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">25</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">if</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000"> ( dllFun )<br /></span>
								<span style="COLOR: #008080">26</span>  </font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">    {<br /></span>
								<span style="COLOR: #008080">27</span> <span style="COLOR: #000000">        dllFun(</span><span style="COLOR: #000000">0</span></font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">28</span>  </font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">    }<br /></span>
								<span style="COLOR: #008080">29</span>  </font>
				</font>
				<font face="Courier New">
						<font size="2">
								<span style="COLOR: #000000">    FreeLibrary(hDll);<br /></span>
								<span style="COLOR: #008080">30</span> <span style="COLOR: #000000">}</span></font>
				</font>
		</div>
		<p>
				<br />动态链接库的一般应用都在这儿了，更加具体的就要去问google了:)。</p>
		<p>
				<font color="#006400">//-------------------------------------------------------------------------------<br />// 异步回调 ( Asynchronism Callback )</font>
		</p>
		<p>今天想说的主要内容是异步回调。大致结构是：</p>
		<p>
				<font color="#006400">//-------------------------------------------------------------------------------<br />//                           IAsyncCaller  IAsyncCallback<br />//                                         \    /<br />// CManager --&gt; CSession --&gt; CEvent<br />//-------------------------------------------------------------------------------<br />// class :  CManager<br />// function : Singleton实现，管理所有CSession对象</font>
		</p>
		<p>
				<font color="#006400">// class :  CSession<br />// function : 处理会话，关联事务</font>
		</p>
		<p>
				<font color="#006400">// class :  CEvent<br />// function : Session的关联对象，处理异步回调<br />// base class: IAsyncCaller, IAsyncCallback</font>
		</p>
		<p>在发起session的时候，new一个CSession对象，为其分配一个GUID，并加入管理session的CManager对象的map(支持多线程操作)，new一个CEvent对象，将该CEvent对象设置为回调响应的host，该CEvent对象可进行其他同步处理。</p>
		<p>当回调条件满足，由CManager通过相应CSession对象触发，并交由其关联的CEvent对象处理。</p>
		<p>如果CEvent应用规模较小，可由CManager的map直接管理，省掉CSession的中间处理。</p>
		<p>这种处理方式的优点是，将普通事务的回调处理机制抽象为通过Session Manager(CManager)进行统一管理，普通事务的处理放到main thread中，线程间通信则交给CManager和CSession，实现了良好封装。</p>
		<p>
				<font color="#006400">//-------------------------------------------------------------------------------<br />// 具体实现这里就不给出了，用到的TX根据上面的描述应该大概知道怎么做了。其他TX如果不清楚的话，<br />// 清楚的话，可以先google其中的一些关键词。动态链接库的部分因为内容很少，因此也只提供基础使用。<br />//<br />// PS: 因为GF学知识产权的，刚好了解到有这样一个<a href="http://creativecommons.org/licenses/by-nc-nd/3.0/" target="_blank">“创作共用”协议</a>，而且最近很多人在讨论<br />// <a href="/minidxer/archive/2008/01/05/40497.html/" target="_blank">cppblog的原创精神问题</a>，于是大家就看到我blog顶部的这个东西:)。<br />// 注释风格也改成自己平时用的了:)。<br />//-------------------------------------------------------------------------------</font>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/41699.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-01-23 11:04 <a href="http://www.cppblog.com/Fox/archive/2008/01/23/asny_callback.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>门窥多线程安全</title><link>http://www.cppblog.com/Fox/archive/2008/01/10/multithread_security.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 09 Jan 2008 20:02:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/01/10/multithread_security.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/40845.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/01/10/multithread_security.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/40845.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/40845.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>一、多线程安全的引入：</p>
		<p>关于什么是多线程、为什么使用多线程的问题，大家可以看看Jim Beveridge &amp; Robert Wiener的<a href="http://www.china-pub.com/computers/common/info.asp?id=4850" target="_blank">《Win32多线程程序设计》</a>（侯捷 译），或者其他随便一本提到多线程的书或文章。这里只是提到Windows环境下多线程容易引发的问题和解决办法。</p>
		<p>1、线程在时间片结束时退出做不到</p>
		<p>由于Windows属于分时操作系统，系统会为每个线程分配响应的时间片使其工作，绝大多数线程不可能在时间片结束的时候完成其工作，而下一个时间片就有可能分配给其他线程。</p>
		<p>2、线程独立做不到</p>
		<p>如果线程间不存在依赖关系，即线程A的执行不依赖于线程B的执行，此时即使线程B被打断，由于线程独立，所以二者也可以相安无事。</p>
		<p>然而，在多线程解决方案中，线程间的通信是频繁而且必要的。线程通信主要有两种情况：</p>
		<p>1) 多个线程共享相同资源；</p>
		<p>2) 一个线程的执行依赖于其他线程的结果或执行情况。</p>
		<p>这时，我们就需要实现共享资源及线程执行的同步。</p>
		<p>二、多线程安全的解决方案：</p>
		<p>因此，多线程安全的目标就是实现共享资源的互斥访问和线程执行的同步通信。</p>
		<p>通过对操作系统的学习，我们知道线程同步主要有以下方法：</p>
		<p>1) 临界段(Critical Section)</p>
		<p>a) 临界资源的取舍，宜少不宜多，宜短不宜长，一个线程只能最多等待一个临界段；</p>
		<p>b) 无法侦测一个临界段是否已经被放弃；</p>
		<p>c) 临界段属于用户对象。</p>
		<p>2) 互斥锁(Mutex)</p>
		<p>同临界段一样，互斥锁也主要用于保证资源的原子访问，二者的不同之处在于：</p>
		<p>a) 互斥锁属于可具名内核对象；</p>
		<p>b) 互斥锁可以跨进程使用，临界段只能用于同一进程内；</p>
		<p>c) 互斥锁可以指定等待时间，而且可以等待其他内核对象。</p>
		<p>3) 事件(Event)</p>
		<p>a) 事件重置具有人工重置和自动重置两种方式，简单说来，二者分别用于多读和单写；</p>
		<p>b) 事件主要用于线程间相互通知(唤醒)；</p>
		<p>C) 事件属于可具名内核对象。</p>
		<p>4) 信号量(Semaphore)</p>
		<p>a) 信号量属于可具名内核对象；</p>
		<p>b) 信号量没有拥有者，可被任一线程释放；</p>
		<p>关于Win32中这四种对象的使用和要点，更详细的介绍可以参照《Win32多线程程序设计》或<a href="http://www.china-pub.com/computers/common/info.asp?id=131" target="_blank">《Windows核心编程》</a>(Jeffrey Richter)等。</p>
		<p>三、多线程安全的实现：</p>
		<p>将对数据（对象、模型、消息、Socket）的I/O处理放在同一个I/O线程中，保证如队列的push/pop操作、链表的insert/delete操作、文件的write操作、socket的recv/send操作、全局变量的write操作等的互斥访问。</p>
		<p>新建独立模块，尤其是使用第三方库的独立模块，大多会创建独立的新线程。此时就需要对新线程中的数据操作加以注意，可以通过对操作数据的加锁访问解决同步问题，当然，更常见的处理方式是将新线程中的数据操作发送到专门的I/O线程中处理。</p>
		<p>总之，多线程安全是个常说常新的话题，现在有人提出<a href="http://www.informatik.uni-trier.de/~ley/db/indices/a-tree/m/Michael:Maged_M=.html" target="_blank">Lock-Free</a>数据结构的解决方案(Maged M. Michael)，也有所谓的<a href="http://www.informatik.uni-trier.de/~ley/db/indices/a-tree/h/Herlihy:Maurice.html" target="_blank">Wait-Free</a>的解决方案(Maurice Herlihy)，而国内网游界的大牛云风同学更是提出了<a href="http://blog.codingnow.com/2007/11/deepcold.html" target="_blank">单线程多进程</a>的观点和解决方案（因为不了解，按字面有可能存在断章取义之嫌）。但不管怎么样，从中至少可以看出，多线程，说来话长。</p>
		<p>零零散散、东拉西扯、不知所云的讲了一些东西，未必正确，更不能当作知识。全当是对<a href="/Fox/archive/2008/01/02/change_mind_2008.html" target="_blank">上次的承诺</a>有个交代。</p>
		<p>
				<font color="#008000">/*****************************************************************************<br /> 想把多线程的问题搞明白，不是说看看操作系统教材，写点多线程读写的代码就够的。且不论孰是孰非，<br /> 单就网上诸多高手新学对加锁策略铺天盖地的争执说辞甚至相互批判指责，足可见多线程开发并非只言<br /> 片语即可挑明。<br /> 为防止陷入细节争论，这里先作声明：小文仅就所学略抒拙见，无意引起争端……<br />*****************************************************************************/</font>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/40845.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-01-10 04:02 <a href="http://www.cppblog.com/Fox/archive/2008/01/10/multithread_security.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调整思路——2008年继续努力</title><link>http://www.cppblog.com/Fox/archive/2008/01/02/change_mind_2008.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 01 Jan 2008 18:43:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/01/02/change_mind_2008.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/40201.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/01/02/change_mind_2008.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/40201.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/40201.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>元旦放假3天，本来想把前面写的一个存在线程安全隐患的模块推倒重来的，可是改着改着就觉得不对劲了。</p>
		<p>既然是返工，就想尽量把现在的理解完全加进去，让后面的人看了不要骂。可是想把几千行的代码改得面目全非并且更加安全准确也并不是一件容易的事，虽然对于功能和逻辑的认识比以前要清晰的多。</p>
		<p>拿到一个新的模块，上面一般会给个大致的deadline。除非你对这个模块和整个项目的依赖关系（接口、逻辑、功能）有很好的把握，否则，你根本不知道到底有多少东西是已经实现的，有多少东西是可以复用的，有多少东西是需要修改的，有多少东西是要重写的，有多少东西是要新加的，仅仅根据需求预估的进度是不可能恰到好处的。而脱离了整个项目实现的模块是非常可能出问题的，尤其是在使用多线程的项目中。</p>
		<p>当我的这个模块完成并上马之后，我沾沾自喜的跟上面说，应该是不会有问题了，上面跟我说了一句：如果不出问题就是奇迹了，我当时颇不以为然。在后面一两周之内真的就是没有什么问题，我真想告诉他是我创造了奇迹。</p>
		<p>“奇迹”在2007年的最后一周破灭了。在<a href="/Fox/archive/2007/12/26/yule_xiling_snow_mount.html" target="_blank">我从西岭雪山回来</a>的那天，为了增加新功能把代码修改了一些，结果第二天更新之后，服务器就老是有问题，找了一下午，才发现在修改代码的时候居然忘记对一个pointer做NULL判定！我心想，这种错误居然都出来了！死了算了！而且这个问题出在非主线程中。然后就和同事在考虑，这个东西如果线程同步出现问题，你就是每次使用前都做NULL判定也没用，所以就决定把这个模块重写了。</p>
		<p>在这儿我就不想就线程安全问题多说了，以后想好了再专门去写点多线程的东西吧，今天只是想说点琐碎的东西。</p>
		<p>因为是放假，心思未必就全部放在上面了，代码没改多少，倒是玩了很长时间的游戏。后来想想，也不全是时间问题，几千行的代码改来改去，难保不出现更多的问题。必须把它当作一个新的模块去写，先要把逻辑结构完全理出来，能多细化就多细化，最好能够精确到变量的使用，而且把文档做细，这样就可以在写文档的过程中把问题尽可能想全想清楚。改代码先改文档，这几乎是所有学过软件工程并写过项目的同学都能认识并理解的常识，可是在实际工作中，上有任务催赶，下有闲心杂念，很难把文档和注释写好。而做不到这一点的话，你就不敢保证你的模块不出差错。</p>
		<p>所以，对于一个一般的需求，如果deadline是2个月的话。读需求、评估依赖关系、量进度要花掉1周，画逻辑结构、写文档要花掉3周，相当于前面一半的时间没有动手写代码，然后写代码大概只用1周，甚至更少，其他时间就留给测试和修改文档、代码了。从软件工程的角度，这样的分配是合理的，而且是应该的，但到了实际项目里面，又做不到！看来，不管是manager，还是coder，都不能急，软件工程不能白学了。</p>
		<p>我发现，我的软件工程就是白学了，以后得改改。</p>
		<p>
				<font color="#008000">/*****************************************************************************<br /> 不想回头去动以前的代码，每次看以前写过的东西，都有一种想把它彻底删除的冲动。<br /> 把需求看好、文档写好、时间安排好，这才是硬道理……</font>
		</p>
		<p>
				<font color="#008000"> 毕竟是新年，还是祝大家：新年快乐！<br /> 重要的是，新的一年，别荒废了……<br />*****************************************************************************/</font>
				<br />
		</p><img src ="http://www.cppblog.com/Fox/aggbug/40201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-01-02 02:43 <a href="http://www.cppblog.com/Fox/archive/2008/01/02/change_mind_2008.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>也说说级数求和(1+2+3...N)和其他</title><link>http://www.cppblog.com/Fox/archive/2007/12/21/simple_series_sum.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Fri, 21 Dec 2007 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2007/12/21/simple_series_sum.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/39190.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2007/12/21/simple_series_sum.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/39190.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/39190.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>对于(1+2+...+N) 的求和，最早就是看高斯的故事，而且说实话，我是没有这样的智商的：</p>
		<p>                sum(1+2+...+N) = N*(N+1)/2</p>
		<p>刚看了一篇<a href="/azhisoft/archive/2007/12/19/436.html" target="_blank">研究该级数求和的文章</a>，虽为调侃，但实在感觉文中纰漏太多，不禁在此多言。</p>
		<p>文中的第一种方法自称标准，而且还能使“全班2/3的同学都用俺的标准应付老师和试卷”，我大为惊诧：</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #008080">1</span> <span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i, sum </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000">;<br /></span>
								<span style="COLOR: #008080">2</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;i </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> N;i </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)sum </span><span style="COLOR: #000000">+=</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000"> i;<br /></span>
								<span style="COLOR: #008080">3</span> <span style="COLOR: #000000">printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1-N的级数和是: %i</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,sum);</span></font>
				</font>
		</div>
		<p>
				<br />显然，printf的结果是N-1个数的和，此处，我更愿意相信是文中的笔误而已。</p>
		<p>第二种和第三种方法让人觉得奇怪：</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #008080">1</span> <span style="COLOR: #0000ff">float</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000"> sum;<br /></span>
								<span style="COLOR: #008080">2</span> <span style="COLOR: #000000">sum </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (N </span><span style="COLOR: #000000">^</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">/</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> N </span><span style="COLOR: #000000">/</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000">;<br /></span>
								<span style="COLOR: #008080">3</span> <span style="COLOR: #000000">printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1-N的级数和是: %i</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,(</span><span style="COLOR: #0000ff">int</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000">)sum);<br /></span>
								<span style="COLOR: #008080">4</span> </font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #008080">5</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">float</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000"> sum;<br /></span>
								<span style="COLOR: #008080">6</span> <span style="COLOR: #000000">sum </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> N </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> (N </span><span style="COLOR: #000000">/</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0.5</span></font>
				</font>
				<font face="Courier New">
						<font size="4">
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">7</span> <span style="COLOR: #000000">printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1-N的级数和是: %i</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)sum);</span></font>
				</font>
		</div>
		<p>
				<br />前面的写法纯属恶搞，^在C/C++中是异或位操作，相信接触过位运算的人都知道这一点，而且当N为奇数时，sum的结果将比真实值少1。后面的写法更是荒唐，当N为奇数时，sum的结果将比真实值相去更远（有兴趣的可以仔细看看）。</p>
		<p>对于后面两种写法，我想说的重点不是这些明显的错误，因为这样的错误只可博众君一笑。但文中定义sum使用float的做法，让我百思不得其解。对于计算机的运算，浮点运算的耗时和整型运算的耗时，那不是一个数量级的。对于该级数运算，我们完全可以避免浮点运算，而且方法在文章一开始，就已经给出了：</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #008080">1</span> <span style="COLOR: #0000ff">int</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000"> sum;<br /></span>
								<span style="COLOR: #008080">2</span> <span style="COLOR: #000000">sum </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> N</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">(N</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">2</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">;<br /></span>
								<span style="COLOR: #008080">3</span> <span style="COLOR: #000000">printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1-N的级数和是: %i</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, sum);</span></font>
				</font>
		</div>
		<p>
				<br />无论N为奇数还是偶数，N*(N+1)一定是偶数，因此，上述方法不存在浮点运算，而且系统会自动将/2的操作优化为右移1位。</p>
		<p>不知怎么，忽然就想到了递归，想到了Fibonacci数列。讲递归的教材都会拿上面的级数求和和Fibonacci数列做例子。其实，我个人感觉这是不恰当的，但想想为了让学生掌握递归算法，也只能举类似的简单的例子。我们也知道，递归计算对于堆栈调用是非常频繁而耗时的，对于求Hanoi塔这样的复杂问题，我不知道不用递归有没有更好的方法，但如果计算Fibonacci数列还是使用递归，在初学递归时是可以原谅的。简单点的方法可以是这样：</p>
		<p>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #008080"> 1</span> <span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> fib_odd </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, fib_even </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000"> ;<br /></span>
								<span style="COLOR: #008080"> 2</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> n </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (N+1)</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">2</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">;<br /></span>
								<span style="COLOR: #008080"> 3</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">n; i</span><span style="COLOR: #000000">++</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000"> )<br /></span>
								<span style="COLOR: #008080"> 4</span> </font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">{<br /></span>
								<span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000">  fib_odd </span><span style="COLOR: #000000">+=</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">  fib_even;<br /></span>
								<span style="COLOR: #008080"> 6</span> <span style="COLOR: #000000">  fib_even </span><span style="COLOR: #000000">+=</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">  fib_odd;<br /></span>
								<span style="COLOR: #008080"> 7</span> </font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">}<br /></span>
								<span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> nFib </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000">;<br /></span>
								<span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">( N </span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000"> )<br /></span>
								<span style="COLOR: #008080">10</span> <span style="COLOR: #000000">  nFib </span><span style="COLOR: #000000">=</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000"> fib_odd;<br /></span>
								<span style="COLOR: #008080">11</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">else</span></font>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #008080">12</span> <span style="COLOR: #000000">  nFib </span><span style="COLOR: #000000">=</span></font>
				</font>
				<font size="4">
						<font face="Courier New">
								<span style="COLOR: #000000"> fib_even;<br /></span>
								<span style="COLOR: #008080">13</span> <span style="COLOR: #000000">printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Fibonacci数列前N项和是: %i</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,nFib); </span></font>
				</font>
		</div>
		<p>
				<br />上面的两段代码中sum和nFib的值不能太大:)。</p>
		<p>常言道，言过必失。但自私一点讲，把自己的错误暴露给别人，可以让自己更好的进步:)，因此，我写下来，提醒自己也提醒大家，更欢迎大家多批评指正。</p><img src ="http://www.cppblog.com/Fox/aggbug/39190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2007-12-21 10:19 <a href="http://www.cppblog.com/Fox/archive/2007/12/21/simple_series_sum.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>反外挂的一点牢骚</title><link>http://www.cppblog.com/Fox/archive/2007/12/20/anti_credit.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 19 Dec 2007 18:08:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2007/12/20/anti_credit.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/39081.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2007/12/20/anti_credit.html#Feedback</comments><slash:comments>18</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/39081.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/39081.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>俗话说，道高一尺，魔高一丈。</p>
		<p>今天在一个群里，有人提到某某算法（3DES）可以杜绝外挂。我当时心里苦笑一声：哥们儿，太逗了。这年头，中国人已经被忽悠怕了。我信鬼信魔，就是不信佛……</p>
		<p>不过想想，如果能在一定程度上打击外挂，也不错，可是讨论了半天，愣是没有给出具体的方案，最后还是不了了之。</p>
		<p>不过，有时间把思路整理整理，提一个稍微好一点的方法也好。</p>
		<p>王城里面，一排排的外挂小号像阅兵一样，嚣张成马了，完全不把我们放在眼里。</p>
		<p>话说回来，连个脱机外挂都防不住，别人还确实没必要把你放在眼里。</p>
		<p>这边Login Server搞了两三个月的验证码，感觉不错，因为不使用外挂的玩家每次都要折腾半天，我们自己人员输入验证码输的都烦，结果没出半个月外挂又开始横行了，感觉比以前还嚣张。</p>
		<p>我是外挂，我得意的笑，我得意的笑……</p>
		<p>敢情是防贼没防住，把贼扔屋里，自己被锁在外面了！</p>
		<p>
				<font color="#008000">/*****************************************************************************<br />  晚上本来想自己写个内挂，可以偷偷懒，可惜对这东西实在是从来没有过研究。<br />  折腾了一晚上，郁郁而终。<br />  技不如人啊！想来都觉得可笑……<br />*****************************************************************************/</font>
				<font color="#000000">
				</font>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/39081.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2007-12-20 02:08 <a href="http://www.cppblog.com/Fox/archive/2007/12/20/anti_credit.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏脚本变量存取优化</title><link>http://www.cppblog.com/Fox/archive/2007/12/17/script_variable_optimize.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Mon, 17 Dec 2007 11:55:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2007/12/17/script_variable_optimize.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/38779.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2007/12/17/script_variable_optimize.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/38779.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/38779.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>在MMORPG中，存在大量的数据文件和脚本文件，这些文件涉及很多变量，当玩家信息需要存取时（上线、下线、保存、服务器交互），即伴随着大量的读写操作。随着游戏中游戏任务的增加，每一个玩家对应的需要数据库存取的脚本变量的数据量也随之线性增长，随着玩家数量的增加，在服务器保存玩家角色信息的时候，通信量的大小是相当可观的，使用多线程读写，可以使服务器的处理能力大幅增强，但网络和数据库承受的压力也会大幅增加。</p>
		<p>当然现在有很多的脚本语言为我们设计任务系统提供了便利，像Lua、Python、Ruby这些动态语言的功能越来越强，而且可以肯定的是，会有越来越多的产品采用这些优秀的语言。但我今天要谈的不是如何使用动态语言，也不是讨论动态语言孰优孰劣的问题，而是对于大量的脚本变量的存取优化。说白了，这对于使用自定义脚本语言的游戏开发人员才更有参考价值。而且我要说的问题很小，小到我只是讲一点点内容，只是我今天下午的一点活，总结下来更多只是为了让自己记住，并不是教育别人。</p>
		<p>假设在整个脚本系统中，存在500个与玩家相关而且需要数据库存取的脚本变量，如果一个游戏世界中拥有3000个在线玩家，平均每个玩家的脚本变量大小为10KB，如果服务器同时保存这3000个玩家的数据（那可不仅仅是脚本变量，当然脚本变量所占的分量比较大就是了），3000×10KB，哦……与此同时，服务器还要进行其实正常的网络通信和逻辑处理（虽然不可能是同一个线程），但服务器承受的压力已经不小了吧，为了减少这种压力，脚本变量成为了一种稀缺资源。<br />为了对脚本变量的存取进行优化，我想到了一个最容易实现的方法。通过对数据库的观察（其实想也想也想得到:)），我发现玩家数据中大量的脚本变量的值都是0或者空字符串，这就为优化提供了很大的一个空间。</p>
		<p>服务器一般都保存有一个脚本变量的配置文件，在这个文件中列出了所有的脚本变量及其默认值。当玩家登录时，服务器将为其依据这个文件为其建立一份拷贝，并从数据库读取这些变量的真实值填充之。因为大量的变量值都是默认值，所以在往数据库保存的时候，是没有必要全部保存的，而只需保存那些不同于默认值的变量名和变量值以及该变量对应的下标即可。下一次从数据库读入的时候根据下标确定哪些变量值需要从数据库中读取就可以了。</p>
		<p>很简单的一个操作，虽然做到了这一点优化，但是对于500个变量的线性读取和其他操作，依然不是一个好的处理方法。</p>
		<p>几点改进的方向，目前只是有个想法：</p>
		<p>1、将玩家与其脚本变量解耦</p>
		<p>并不是所有的玩家都需要500个脚本变量的，不同等级的玩家可以参与的任务和活动是完全不同的，我们显然没有必要为每一个玩家从生到死都保持这500个变量。这样考虑下来，估计一个玩家的脚本变量数可以减少300-400个，从而实现了“垃圾”回收再利用。OMG！</p>
		<p>想法是非常具有诱惑力的，但这一优化同时涉及到脚本策划和程序，而且稍有不慎（对某一变量重复使用），全盘皆输，在“稳定压倒一切”的大方针下，这样的优化需要给出一个系统的策略，玩家等级、职业因素的影响都要考虑进去。</p>
		<p>2、对玩家脚本变量实现压缩存储</p>
		<p>未经压缩的脚本变量，每个大概有几十Bytes，如果采用一个好的压缩算法，能不能减少到10Bytes呢？什么又是一个好的压缩算法呢？压缩解压缩的成本和直接存取成本比起来哪个更高呢？想想这些的确也都是问题呢。</p>
		<p>
				<font color="#008000">/*****************************************************************************<br />  这只是我工作中的一个总结，问题很简单，也很琐碎，正如我前面所提的，仅仅是提供一个参考。<br />*****************************************************************************/</font>
		</p><img src ="http://www.cppblog.com/Fox/aggbug/38779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2007-12-17 19:55 <a href="http://www.cppblog.com/Fox/archive/2007/12/17/script_variable_optimize.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MMORPG中游戏世界的构建</title><link>http://www.cppblog.com/Fox/archive/2007/12/16/game_world_architecture.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sat, 15 Dec 2007 21:24:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2007/12/16/game_world_architecture.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/38600.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2007/12/16/game_world_architecture.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/38600.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/38600.html</trackback:ping><description><![CDATA[<p>Author: Fox<br /><span><br />一个</span><span>MMORPG</span><span>（</span><span>Massively Multiplayer Online Role Playing Game</span><span>）的架构包含客户端和服务器两部分。客户端主要涉及计算机图形学、物理学、多媒体技术等，服务器主要涉及网络通信技术、数据库技术，而人工智能、操作系统等计算机基础学科知识的应用体现在</span><span>MMORPG</span><span>开发过程中的方方面面。</span></p>
		<p>
				<span>一、游戏世界的划分</span>
		</p>
		<p>
				<span>理想状态的游戏世界仅由一个完整的场景组成，在《魔兽争霸</span>
				<span>III</span>
				<span>》、《</span>
				<span>CS</span>
				<span>》这样的单机游戏中，所有玩家位于该场景中，在理论上，位于该场景中的任意玩家都可以看到游戏中所有玩家并与之交互，出于公平性和游戏性（而不是技术上）的考虑，游戏中并不会这样做。</span>
		</p>
		<p>
				<span>然而，目前的</span>
				<span>MMORPG</span>
				<span>中，几乎没有任何一款可以做到整个游戏世界只包含一个场景，因为在一款</span>
				<span>MMORPG</span>
				<span>中，同时在线的玩家数量成百上千，甚至是数万人同时在一个游戏世界中交互。以现在的网络技术和计算机系统，还无法为这么多玩家的交互提供即时处理。因此，</span>
				<span>MMORPG</span>
				<span>的游戏世界被划分为大小不等、数量众多的场景，游戏服务器对于这些场景的处理分为分区和无缝两种。</span>
		</p>
		<p>
				<span>在分区式服务器中，一个场景中的玩家无法看到另一个场景中的玩家，当玩家从一个场景到另外一个场景跨越时，都有一个数据转移和加载的过程（尤其是从一个分区服务器跨越到另外一个服务器时），玩家都有一个等待的时间，在这段时间内，服务器的主要工作是实现跨越玩家数据的转移和加载以及后一个场景中玩家、</span>
				<span>NPC</span>
				<span>等数据的传输，客户端的主要工作是实现新场景资源的加载和服务器通信。主要时间的长短主要取决于后一个场景中资源数据的大小。分区式服务器的优点主要是各分区服务器保持相对独立，缺点是游戏空间不够大，而且，一旦某个分区服务器中止服务，位于该服务器上的所有玩家将失去连接。</span>
		</p>
		<p>
				<span>所谓无缝服务器，玩家几乎察觉不到场景之间的这种切换，在场景间没有物理上的屏障，对于玩家而言，众多场景构成了一个巨大的游戏世界。场景之间，甚至服务器之间“没有了”明确的界线。因此，无缝服务器为玩家提供了更大的游戏空间和更友好的交互，实现了动态边界的无缝服务器甚至可以在某个服务器中止服务时，按一定策略将负载动态分散到其他服务器。因此，无缝服务器在技术上要比分区服务器更加复杂。</span>
		</p>
		<p>
				<span>目前国内上市的</span>
				<span>MMORPG</span>
				<span>，大多采用分区式服务器，做到无缝世界的主要有《完美世界》和《天下贰》等，国外的</span>
				<span>MMORPG</span>
				<span>中，像《魔兽世界》、《</span>
				<span>EVE</span>
				<span>》等，都实现了无缝世界。</span>
		</p>
		<p>
				<span>无缝服务器与分区式服务器在技术上的主要区别是，当位于场景</span>
				<span>S1</span>
				<span>中的玩家</span>
				<span>P1</span>
				<span>处于两个（甚至更多）场景</span>
				<span>S1</span>
				<span>、</span>
				<span>S2</span>
				<span>的边界区域内时，要保证</span>
				<span>P1</span>
				<span>能够看到场景</span>
				<span>S2</span>
				<span>中建筑、玩家、</span>
				<span>NPC</span>
				<span>等可感知对象。而且边界区域的大小要大于等于</span>
				<span>P1</span>
				<span>可感知的范围，否则就可能发生</span>
				<span>S2</span>
				<span>中的可感知对象突然闪现在</span>
				<span>P1</span>
				<span>视野中的异常。</span>
		</p>
		<p>
				<span>无疑，无缝世界为玩家提供了更人性化和更具魅力的用户体验。</span>
		</p>
		<p>
				<span>二、无缝世界游戏服务器的整体架构</span>
		</p>
		<p>
				<span>MMORPG</span>
				<span>的服务器架构从功能上主要划分为三种：</span>
		</p>
		<p>
				<span>
						<span>1、</span>
				</span>
				<span>登录服务器（</span>
				<span>Login Server</span>
				<span>）</span>
		</p>
		<p>
				<span>登录服务器用于玩家验证登录，并根据系统记录玩家信息得到其所在节点服务器，并通过世界服务器为登录玩家和对应节点服务器建立连接。</span>
		</p>
		<p>
				<span>
						<span>2、</span>
				</span>
				<span>世界服务器（</span>
				<span>World Server</span>
				<span>）</span>
		</p>
		<p>
				<span>世界服务器将整个游戏世界划分成不同场景，将所有场景按一定策略分配给节点服务器，并对节点服务器进行管理。世界服务器的另一功能是与登录服务器交互。因此，世界服务器是登录服务器、节点服务器的沟通桥梁，当然，一旦玩家登录成功，世界服务器将主要处理节点服务器间的通信。因此，世界服务器对于玩家是透明的。</span>
		</p>
		<p>
				<span>
						<span>3、</span>
				</span>
				<span>节点服务器（</span>
				<span>Node Server</span>
				<span>）</span>
		</p>
		<p>
				<span>节点服务器负责管理位于该节点的所有玩家、</span>
				<span>NPC</span>
				<span>的所有交互，在无缝世界游戏中，由于边界区域的存在，一个节点服务器甚至要处理相邻节点上位于边界区域的玩家和</span>
				<span>NPC</span>
				<span>的信息。</span>
		</p>
		<p>
				<span>在具体实现上，不同的</span>
				<span>MMORPG</span>
				<span>为了便于管理，可能还会具有</span>
				<span>AI</span>
				<span>服务器、日志服务器、数据库缓存服务器、代理服务器等。</span>
		</p>
		<p>
				<span>
						<span>三、</span>
				</span>
				<span>无缝世界游戏服务器的主要技术需求</span>
		</p>
		<p>
				<span>
						<span>1、</span>
				</span>
				<span>编程语言（</span>
				<span>C/C++</span>
				<span>、</span>
				<span>SQL</span>
				<span>、</span>
				<span>Lua</span>
				<span>、</span>
				<span>Python</span>
				<span>）</span>
		</p>
		<p>
				<span>
						<span>2、</span>
				</span>
				<span>图形库（</span>
				<span>Direct 3D</span>
				<span>、</span>
				<span>OpenGL</span>
				<span>）</span>
		</p>
		<p>
				<span>
						<span>3、</span>
				</span>
				<span>网络通信（</span>
				<span>WinSock</span>
				<span>、</span>
				<span>BSD Socket</span>
				<span>，或者</span>
				<span>ACE</span>
				<span>）</span>
		</p>
		<p>
				<span>
						<span>4、</span>
				</span>
				<span>消息、事件、多线程、</span>
				<span>GUI</span>
		</p>
		<p>
				<span>
						<span>5、</span>
				</span>
				<span>OS</span>
		</p>
		<p>
				<span>三、无缝世界游戏服务器需要解决的主要问题</span>
		</p>
		<p>
				<span>
						<span>1、</span>
				</span>
				<span>资源管理</span>
		</p>
		<p>
				<span>无论是服务器还是客户端，都涉及到大量资源：玩家数据、</span>
				<span>NPC</span>
				<span>数据、战斗公式、模型资源、通信资源等。当这些资源达到一定规模，其管理的难度不可忽视。而且，资源管理的好坏，直接关系到游戏的安全和生命。</span>
		</p>
		<p>
				<span>
						<span>2、</span>
				</span>
				<span>网络安全</span>
		</p>
		<p>
				<span>安全永远是第一位的，我们无法指望所有的玩家及其所持的客户端永远是友好的。事实上，威胁到游戏的公平性和安全性的大多数问题，归根结底，都是由于网络通信中存在的欺骗和攻击造成的，这些问题包含但不限于交易欺骗、物品复制。</span>
		</p>
		<p>
				<span>
						<span>3、</span>
				</span>
				<span>逻辑安全</span>
		</p>
		<p>
				<span>逻辑安全按理说应该是游戏中最基本的考虑，覆盖的范围也最广最杂。随机数系统是一个非常值得重视的问题，随机数不仅仅用于玩家可见的一些任务系统、战斗公式、人工智能、物品得失等，还可用于网络报文加密等。因此，随机数系统本身的安全不容忽视。另外一个常见的逻辑安全是玩家的移动，最主要的就是防止加速齿轮这样的变态操作。</span>
		</p>
		<p>
				<span>
						<span>4、</span>
				</span>
				<span>负载均衡</span>
		</p>
		<p>
				<span>MMORPG</span>
				<span>中的负载均衡包括客户端及服务器资源管理和逻辑处理的负载均衡，其中最难预知的是网络通信的负载均衡，正常情况下的网络通信数量是可以在游戏设计时做出评估的，但因恶意攻击造成的网络负载是无法预测的。因此，负载均衡所要处理的主要是实时动态负载均衡和灾难恢复。负载均衡需要解决的问题包括负载监控、负载分析、负载分发和灾难恢复。</span>
		</p>
		<p>
				<span>
						<span>5、</span>
				</span>
				<span>录像系统</span>
		</p>
		<p>
				<span>录像系统的构建，主要用于重现关键数据的输入输出，如玩家交易、玩家充值，或者当</span>
				<span>bug</span>
				<span>出现后，为逻辑服务器（泛指上文提到的所有类型服务器，主要是节点服务器）相应部分启动录像系统。待收集到足够数据后，通过录像系统重现</span>
				<span>bug</span>
				<span>。为了使逻辑服务器不受自身时间（如中断调试等）的影响，还可以专门设计心跳服务器来控制数据传输。</span>
		</p>
		<p>
				<span>四、总结</span>
		</p>
		<p>
				<span>在</span>
				<span>MMORPG</span>
				<span>中，真正的</span>
				<span>bug</span>
				<span>永远存在于将来。从这一点出发，关于</span>
				<span>MMORPG</span>
				<span>中游戏世界的构建，怎样苛刻的思考都不为过。<br /><br />参考资料：</span>
		</p>
		<p>
				<span>1、 [美] Kim Pallister编, 孟宪武 等译. 游戏编程精粹5, P467-474, P516. 人民邮电出版社, 2007年9月. 北京.<br />2、 [美] Thor Alexander编, 史晓明 译. 大型多人在线游戏开发, P174-185. 人民邮电出版社, 2006年12月. 北京.<br />3、 [美] Dante Treglia编, 张磊 译. 游戏编程精粹3, P117-122. 人民邮电出版社, 2003年7月. 北京.<br />4、 [美] Mark DeLoura编, 王淑礼 等译. 游戏编程精粹1, P90-93. 人民邮电出版社, 2004年10月. 北京.<br />5、 [美] Douglas 等著, 於春景 译. C++网络编程 卷1. 中国电力出版社, 2004年11月. 北京.<br />6、 [美] Stephen D. Huston 等著, 马维达 译. ACE程序员指南. 中国电力出版社, 2004年11月. 北京.<br />7、 [美] Erich Gamma等著, 李英军 等译. 设计模式. 机械工业出版社, 2000年6月. 北京.<br />8、 游戏引擎全剖析. <a href="http://bbs.gameres.com/showthread.asp?threadid=101293">http://bbs.gameres.com/showthread.asp?threadid=101293</a>.<br />9、 服务器结构探讨：登录服的负载均衡. <a href="http://gamedev.csdn.net/page/351491d0-05ad-48a4-85e1-77870bc1eef3">http://gamedev.csdn.net/page/351491d0-05ad-48a4-85e1-77870bc1eef3</a>.<br />10、服务器结构探讨：最终的结构. <a href="http://gamedev.csdn.net/page/28695655-974c-4291-8ac4-2589c4e770d3">http://gamedev.csdn.net/page/28695655-974c-4291-8ac4-2589c4e770d3</a>.<br />11、谈谈网络游戏服务器解决方案. <a href="http://www.beareyes.com.cn/2/lib/200411/08/20041108102.htm">http://www.beareyes.com.cn/2/lib/200411/08/20041108102.htm</a>.<br />12、负载均衡——大型在线系统实现的关键(下篇)（服务器集群架构的设计与选择）. <a href="http://blog.csdn.net/sodme/archive/2005/06/15/394576.aspx">http://blog.csdn.net/sodme/archive/2005/06/15/394576.aspx</a>.<br />13、云风的BLOG. <a href="http://blog.codingnow.com/">http://blog.codingnow.com/</a><br /></span>
		</p>
		<span style="COLOR: #008000">/*****************************************************************************<br />  从0:00到5:00，在写这篇随笔的过程中，我翻找、点击着上面的这些资料，其实还有更<br />  多的资料，没有记在上面，算是为开题做的准备。现在依然是睡意全无。越写越觉得<br />  不够，越想越觉得还有更多东西写不出来……<br />  PS：这些资料大都不是第一次翻，以前看这些资料大多只是单纯的看，现在有目的的<br />  看，才觉得都写得很有味道。不管是不是同意所有观点，都不是本文讨论的重点。<br />*****************************************************************************/</span><img src ="http://www.cppblog.com/Fox/aggbug/38600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2007-12-16 05:24 <a href="http://www.cppblog.com/Fox/archive/2007/12/16/game_world_architecture.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>