Creative Commons License
本Blog采用 知识共享署名-非商业性使用-禁止演绎 3.0 Unported许可协议 进行许可。 —— Fox <游戏人生>

游戏人生

游戏人生 != ( 人生 == 游戏 )
站点迁移至:http://www.yulefox.com。请订阅本博的朋友将RSS修改为http://feeds.feedburner.com/yulefox
posts - 62, comments - 508, trackbacks - 0, articles - 7

Author: Fox

//-----------------------------------------------------------------------------------------------------
夜深了,随便写写……
//-----------------------------------------------------------------------------------------------------

大凡学过编程语言和网络的TX应该都写过自己的聊天程序,那时候大家都知道了套接字怎么selectconnectbindlistenacceptsendrecv,也知道了TCPUDP的区别……稍微用功的TX或许还写过多人聊天程序,知道了什么是阻塞I/O,真正致力于向QQ、MSN等即时聊天工具靠齐的大牛对本文提到的IOCP更是了然于胸。更多的TX或者有兴趣继续看下去。

一、阻塞I/O(主要指TCP)

1、当socket的recv buff为空时,进程会wait直到新数据到达;

2、当socket的send buff已满时,进程会wait直到空间足够;

3、当socket的accept没有新连接到达,进程会wait直到新连接到达;

4、当socket的connect没有收到ACK,进程会wait直到收到ACK。

而非阻塞I/O则是致力于提供高效的异步I/O。

二、IOCP(I/O Completion PortI/O完成端口

IOCP是MS提供的Windows内核对象,内部使用线程池管理,并根据CPU的个数确定线程个数。当数据到达后,统一投递到唯一的IOCP队列,对应的若干工作线程用于处理这些数据,从而实现非阻塞异步I/O。

简单了解了IOCP的功能和原理,下面提供几点线索,供有兴趣的TX整理思绪J

1、OVERLAPPED结构:

2、CreateIoCompletioPort:用于创建IOCP,关联连接来的socket句柄,用于接收数据;

3、GetQueuedCompletionStatus:供工作线程调用,取到数据的线程会加入I/O完成队列,IOCP的线程池管理这些工作线程。

三、深入学习和使用

1、Jeffrey Richter的《Advanced Windows》,第15章,谁看谁知道J

2、Jim Beveridge & Robert Wiener的《Multithreading Applications in Win32》,第6章,谁看谁知道J

3、Google

//-----------------------------------------------------------------------------------------------------
感觉用Office 2007编辑和发布Blog比Live Writer要方便很多,主要是Live Writer的编辑功能太少了,如果2007能够对链接进行target设置,
再支持EntryName就perfact了J
从新公司回来,还没有完全适应这边宽松的环境,这几天好似梦游一般,先是IE出问题,Ghost了一道,后面是Outlook收邮件出问题。
还是夜深人静的时候,一个人燃着烟、听着歌、喝着茶、敲着键盘有感觉……
//-----------------------------------------------------------------------------------------------------

posted @ 2008-03-06 01:18 Fox 阅读(4407) | 评论 (7)编辑 收藏

Author: Fox

//-----------------------------------------------------------------------------------------------------
因为要归位回原公司了,手上便没有什么工作了,难得清闲下来,就整理一些很杂的东西,准备下周回去了J
//-----------------------------------------------------------------------------------------------------

零、关于此文

下面的东西很杂,但并非没有关联。

一、关于《疯狂的程序员》

有些搞程序的人有个癖性:自负偏激,主观绝对。

早就看过一点儿,因为时间,没有怎么关注,下午就找来CSDN的blog上面连载的《疯狂的程序员》来看。

正如很多人所评论的,在绝影身上,大家都找到了自己当初学程序的影子。哪个稍有点技术的程序没有点自负的心理呢?绝影的性格很偏激,人很要面子,想法很阴暗,对世界的认识很主观、很绝对。

可惜的是,这个东西,只能当作小说看,其他不做评论……

二、关于Windows的环境变量

有些搞程序的人有个癖性:能用键盘的坚决不用鼠标。

查看帮助,按F1,重命名,按F2,搜索,按F3,输入地址,按F4,刷新,按F5……

桌面上很干净,没有"我的电脑"的图标,都用WinKey+E。没有IE的图标,都用WinKey+R,输入iexplore,回车……

快速启动里面没有"显示桌面"的图标,都用WinKey+D,或者WinKey+M,没有Outlook的图标,都用WinKey+R,输入outlook,回车,Word就输入winword,记事本就输入notepad……

打开大多程序,不用鼠标到处点击,都是"运行"里面输入命令行替代了。除了Windows默认的这些,自己常用的其他软件怎么办呢?Windows有个环境变量。下面我给大家show一下,怎么不用鼠标,完成自定义环境变量,实现命令打开任一软件J

1、WinKey+E,打开"我的电脑";

2、Alt+Enter,打开其"属性";

3、方向键,选择"高级";

4、Alt+N,打开"环境变量";

5、Tab键,选择"系统变量";

6、方向键,选择"Path";

7、Alt+I,打开"编辑";

8、End键,移动到最后;

9、输入";targetpath";*

10、Tab键,选择"确定",回车,Tab键,选择"确定",回车;

11、WinKey+R,打开"运行";

12、输入"softname",回车;*

13、Over。

//-----------------------------------------------------------------------------------------------------
其中,targetpath为soft所在文件夹绝对路径,softname为软件对应的exe文件名(.exe可省略)……
//-----------------------------------------------------------------------------------------------------

posted @ 2008-02-29 18:11 Fox 阅读(1744) | 评论 (3)编辑 收藏

Author: Fox

//-----------------------------------------------------------------------------------------------------
关于反外挂,这两天在和几位同事和网友讨论的结果依然是,更多的要从策划角度解决……
//-----------------------------------------------------------------------------------------------------

最近在考虑安全问题的时候,在《游戏编程精粹3》中看到Pete Isensee的《安全套接字》(即通常所说的Secure Socket Layer, SSL技术),又Google了一些IPSec的相关资料。尽管IPSec是部署在IP层的协议,但它还是可以为我们提供一些思路。

一、IPSec的认证安全(AH+ESP)

1、不可否认性:采用公钥加密的数字签名具有抗抵赖性。

2、防止报文重放:使用序列号和滑动窗口以保证数据包的唯一性,即使数据包被截获重发,也会因序列号的相同或者错误而被抛弃。

3、完整性:IPSec使用单独的鉴别头部(Authentication Header, AH)信息进行校验,防止报文篡改,校验的算法主要是MD5、SHA-1等单向哈希算法。

4、可靠性:通过加密封装安全有效载荷(Encapsulating Security Payload, ESP),IPSec对传输数据进行保护,加密算法除了MD5、SHA-1,还有加密块链接(Cipher Block Chaining, CBC)模式加密算法等。

二、IPSec的数据加密

在数据加密上,IPSec使用的主要是DES(Data Encryption Standard)和3DES(Triple Data Encryption Standard)算法。

三、IPSec的密钥管理

为了保证数据传输安全,IPSec使用由IKE(Internet Key Exchange)提供的动态密钥更新机制,Diffie-Hellman算法提供密钥生成策略,通信两端需要维持一个安全关联(Security Association),为两端通信指定认证及加密所用算法和密钥,并提供序列号和滑动窗口等。

需要注意的是,IPSec并没有提供数据产生到发送之前的保护机制。举例来说,就是IPSec可以在最大程度上保证你输入的帐号密码在传输过程中的安全,但并不能防止钓鱼软件和其他木马在你输入这些信息时被截获L,那应该是你要注意的。

对IPSec有兴趣的TX可以到http://www.ietf.org上下载相关的RFC文档研究研究J

//-----------------------------------------------------------------------------------------------------
本以为手上工作完成,可以偷时间看看安全方面的东西,不曾想Joe又分下了新任务L……
//-----------------------------------------------------------------------------------------------------

posted @ 2008-02-28 20:54 Fox 阅读(2074) | 评论 (3)编辑 收藏

Author: Fox

//-----------------------------------------------------------------------------------------------------
此篇仅是对反脱机外挂的一点思考,其他安全问题如登录验证、消息验证等更多的是涉及逻辑功能。
//-----------------------------------------------------------------------------------------------------

春节刚回来的时候,回公司去和Soft聊到了自己的毕业论文的问题,因为专业的关系,我必须给出一些安全方面的考虑,正是因为这一点,我当时开题时就立足对安全的无缝游戏世界进行思考。只是在游戏本身的安全性上,一直也没有一个好的出发点,这两周还是在考虑这个问题。

这一点,有我入行时间不长,对于游戏本身、玩家与开发者(含游戏及外挂、木马开发者)之间的关系并没有一个很好的把握,更多的是由于我对游戏中的可用的安全技术不了解,尤其是对应用层安全协议不了解,对破解技术也不了解,导致无所适从。

《游戏编程精粹1》中Andrew Kirmse在《在线游戏的网络协议》一文中对常见的篡改报文、报文重放和逆向工程有讲述。预防报文篡改的有效防御是哈希校验,现在大多游戏是使用MD5算法,而且网上开源的MD5代码也很多。对于报文重放,Andrew提到了使用线性叠加随机数的状态机,具体原理和实现方式因为没有提到太详细,还要针对实际应用继续学习L。然而,由于客户端既是报文的接收者也是发送者,因此,客户端包括了完整的加解密算法。一旦客户端被逆向,上述措施就变成了破解者背后的烟雾弹,完全失去意义。

提到反外挂,Joe的看法也是说这个东西和具体某一个技术关系不大,还是要从机制上去看。加不加密对于普通玩家没有意义,对于专业从事逆向的人更是也没有意义,所有单纯考虑加密是没有效果的。对于免费游戏,外挂往往是打钱公司的工具,你封他的号,他再建就是了,代价几乎为0,而一般付费游戏(像魔兽世界)一个帐号对应一个CDKey,一个CDKey就要几十块钱,这个封起来就有点咬牙了。

说到这里,不妨换个思路:为免费游戏加入CDKey。我一款游戏从内测、封测到公测,让玩家充分参与体验,在被逆向且外挂横行之前,按正常逻辑运营。进而假定我这一款游戏在公测之后,让玩家感觉魅力十足。引导玩家并实施CDKey,一个CDKey大约会需要玩家付出些许Money以示诚意,在玩家游戏过程中,会阶段性向玩家赠送部分增值道具。老玩家在进入新区时,需要申请继续使用原CDKey。这样一来,外挂就不会肆无忌惮了。

BTW,这个思路没有从技术角度解决问题,下面再来看一种略微关乎技术实现的解决方案:动态验证。在游戏运行期间,会不定期的向玩家发送验证码,客户端在收到消息后,必须在一定时间内响应,向服务器确认收到的验证码,否则将被强制下线,再次登录后将更加频繁的收到验证码,直到用其良好的回复次数累积消除其不良记录为止。为了尽量减少因此给玩家造成的不友好体验,在任务场景、重要PK场景或者高等级玩家活动场景,验证码的发送和确认可适当放宽

当然,如果外挂中加入了图形识别,这一招也未必奏效。

不知是道高还是魔高,可以肯定的一点是:大家都是在利益的驱动下绞尽脑汁。

//-----------------------------------------------------------------------------------------------------
春节回来之后,一直比较忙(确切的说是比较懒),没有更新,宜更加勤奋。
最近工作涉及到数据库编程,一点点对数据库的读写居然耗掉我3天时间,汗!
//-----------------------------------------------------------------------------------------------------

posted @ 2008-02-26 16:04 Fox 阅读(2597) | 评论 (10)编辑 收藏

Author: Fox

终于赶在周末之前调通了,现在来总结一下我这个项目中对于异步回调的应用背景。

这个项目的内容就是在游戏中使用第三方库为所有玩家提供更好的服务,当server启动后,加载dll,初始化该模块,当server退出时,结束模块功能,卸载dll。

当玩家提出请求后,server在main thread中通过lib转发玩家请求,lib处理完毕,在其独立thread中回调server为其实现的callback function。此时,server需要将返回的result转到main thread中对result及其相关的玩家数据进行处理。

第三方库的需求是很明确的,在合适的地方发送请求,在合适的地方处理响应。

Joe对我的要求也是很明确的,响应处理时采用server当前架构(这个架构在上一篇文中有提到),使我的编码不涉及任何游戏功能逻辑处理,并使整个处理流程细节对后续应用开发透明。

二者结合起来,就为这个项目融入整个server的架构提供了完美的需求,也为我的编码提供了最小限度的选择空间:(,好处是后续功能开发可以完全无视我的编码,只需实现对回调响应后的功能,只有server底层知悉如何调用。

给出序列图:

 

uml_asny_callback

为了保持对上层开发透明,OnCallback需要封装。

//-------------------------------------------------------------------------------
// 一年来,我主要参与了两款游戏,确切的说是半年,前面半年并没有真正涉及运营产品的开发,只是做工具。
// 现在这个模块是我做的最快,也是压力最大的一个。现在想来,原因在于此模块涉及到游戏主逻辑底层和
// 第三方动态链接库的通信及处理。
// 在短短几天的时间内让你的设计满足第三方库的应用需求并符合游戏自身底层逻辑的设计风格,的确有些痛苦,
// 好在有Joe的指点,让我在完成工作的同时又学到了一些方法:)。
//-------------------------------------------------------------------------------

posted @ 2008-01-25 11:27 Fox 阅读(1533) | 评论 (4)编辑 收藏

Author: Fox

前段时间写过一篇关于线程安全的文字,有TX觉得不深入。因为本来就没想写的太具体,只是随便说说,今天就想说点具体的技术。

//-------------------------------------------------------------------------------
// 动态链接库 (Dynamic Link Library)

1) 动态链接;

2) 跨语言;

3) Win32平台可用;

 1 //  静态链接库.h文件中对函数的声明:
 2 // dllExam.h

 3 extern "C" void /*__stdcall*/ Func( int  nParam );
 4 

 5 //  动态链接库.h文件中对函数的声明:
 6 // dllExam.h

 7 extern "C" void __declspec( dllexport ) /*__stdcall*/ Func( int  nParam );
 8 

 9 // 动态链接库的静态调用:
10 #pragma comment(lib,"dllExam.lib"
11 extern "C" __declspec(dllimport) /*__stdcall*/ Func( int
 nParam );
12 

13 dllFun(0 );
14 

15 //  动态链接库的动态调用:
16 // useDllExam.cpp

17 typedef void(/*__stdcall*/ *CallFun )( int );    // 宏定义,方便使用
18 
19 HINSTANCE hDll;                        // DLL句柄
20 CallFun dllFun;                        // 库函数指针
21 hDll = LoadLibrary( "dllExam.dll"  );
22 if
( hDll )
23 
{
24     dllFun = (CallFun)GetProcAddress(hDll, "Func"
);
25     if
 ( dllFun )
26 
    {
27         dllFun(0
);
28 
    }
29 
    FreeLibrary(hDll);
30 }


动态链接库的一般应用都在这儿了,更加具体的就要去问google了:)。

//-------------------------------------------------------------------------------
// 异步回调 ( Asynchronism Callback )

今天想说的主要内容是异步回调。大致结构是:

//-------------------------------------------------------------------------------
//                           IAsyncCaller  IAsyncCallback
//                                         \    /
// CManager --> CSession --> CEvent
//-------------------------------------------------------------------------------
// class :  CManager
// function : Singleton实现,管理所有CSession对象

// class :  CSession
// function : 处理会话,关联事务

// class :  CEvent
// function : Session的关联对象,处理异步回调
// base class: IAsyncCaller, IAsyncCallback

在发起session的时候,new一个CSession对象,为其分配一个GUID,并加入管理session的CManager对象的map(支持多线程操作),new一个CEvent对象,将该CEvent对象设置为回调响应的host,该CEvent对象可进行其他同步处理。

当回调条件满足,由CManager通过相应CSession对象触发,并交由其关联的CEvent对象处理。

如果CEvent应用规模较小,可由CManager的map直接管理,省掉CSession的中间处理。

这种处理方式的优点是,将普通事务的回调处理机制抽象为通过Session Manager(CManager)进行统一管理,普通事务的处理放到main thread中,线程间通信则交给CManager和CSession,实现了良好封装。

//-------------------------------------------------------------------------------
// 具体实现这里就不给出了,用到的TX根据上面的描述应该大概知道怎么做了。其他TX如果不清楚的话,
// 清楚的话,可以先google其中的一些关键词。动态链接库的部分因为内容很少,因此也只提供基础使用。
//
// PS: 因为GF学知识产权的,刚好了解到有这样一个“创作共用”协议,而且最近很多人在讨论
// cppblog的原创精神问题,于是大家就看到我blog顶部的这个东西:)。
// 注释风格也改成自己平时用的了:)。
//-------------------------------------------------------------------------------

posted @ 2008-01-23 11:04 Fox 阅读(2413) | 评论 (4)编辑 收藏

Author: Fox

一、多线程安全的引入:

关于什么是多线程、为什么使用多线程的问题,大家可以看看Jim Beveridge & Robert Wiener的《Win32多线程程序设计》(侯捷 译),或者其他随便一本提到多线程的书或文章。这里只是提到Windows环境下多线程容易引发的问题和解决办法。

1、线程在时间片结束时退出做不到

由于Windows属于分时操作系统,系统会为每个线程分配响应的时间片使其工作,绝大多数线程不可能在时间片结束的时候完成其工作,而下一个时间片就有可能分配给其他线程。

2、线程独立做不到

如果线程间不存在依赖关系,即线程A的执行不依赖于线程B的执行,此时即使线程B被打断,由于线程独立,所以二者也可以相安无事。

然而,在多线程解决方案中,线程间的通信是频繁而且必要的。线程通信主要有两种情况:

1) 多个线程共享相同资源;

2) 一个线程的执行依赖于其他线程的结果或执行情况。

这时,我们就需要实现共享资源及线程执行的同步。

二、多线程安全的解决方案:

因此,多线程安全的目标就是实现共享资源的互斥访问和线程执行的同步通信。

通过对操作系统的学习,我们知道线程同步主要有以下方法:

1) 临界段(Critical Section)

a) 临界资源的取舍,宜少不宜多,宜短不宜长,一个线程只能最多等待一个临界段;

b) 无法侦测一个临界段是否已经被放弃;

c) 临界段属于用户对象。

2) 互斥锁(Mutex)

同临界段一样,互斥锁也主要用于保证资源的原子访问,二者的不同之处在于:

a) 互斥锁属于可具名内核对象;

b) 互斥锁可以跨进程使用,临界段只能用于同一进程内;

c) 互斥锁可以指定等待时间,而且可以等待其他内核对象。

3) 事件(Event)

a) 事件重置具有人工重置和自动重置两种方式,简单说来,二者分别用于多读和单写;

b) 事件主要用于线程间相互通知(唤醒);

C) 事件属于可具名内核对象。

4) 信号量(Semaphore)

a) 信号量属于可具名内核对象;

b) 信号量没有拥有者,可被任一线程释放;

关于Win32中这四种对象的使用和要点,更详细的介绍可以参照《Win32多线程程序设计》或《Windows核心编程》(Jeffrey Richter)等。

三、多线程安全的实现:

将对数据(对象、模型、消息、Socket)的I/O处理放在同一个I/O线程中,保证如队列的push/pop操作、链表的insert/delete操作、文件的write操作、socket的recv/send操作、全局变量的write操作等的互斥访问。

新建独立模块,尤其是使用第三方库的独立模块,大多会创建独立的新线程。此时就需要对新线程中的数据操作加以注意,可以通过对操作数据的加锁访问解决同步问题,当然,更常见的处理方式是将新线程中的数据操作发送到专门的I/O线程中处理。

总之,多线程安全是个常说常新的话题,现在有人提出Lock-Free数据结构的解决方案(Maged M. Michael),也有所谓的Wait-Free的解决方案(Maurice Herlihy),而国内网游界的大牛云风同学更是提出了单线程多进程的观点和解决方案(因为不了解,按字面有可能存在断章取义之嫌)。但不管怎么样,从中至少可以看出,多线程,说来话长。

零零散散、东拉西扯、不知所云的讲了一些东西,未必正确,更不能当作知识。全当是对上次的承诺有个交代。

/*****************************************************************************
 想把多线程的问题搞明白,不是说看看操作系统教材,写点多线程读写的代码就够的。且不论孰是孰非,
 单就网上诸多高手新学对加锁策略铺天盖地的争执说辞甚至相互批判指责,足可见多线程开发并非只言
 片语即可挑明。
 为防止陷入细节争论,这里先作声明:小文仅就所学略抒拙见,无意引起争端……
*****************************************************************************/

posted @ 2008-01-10 04:02 Fox 阅读(2700) | 评论 (10)编辑 收藏

Author: Fox

元旦放假3天,本来想把前面写的一个存在线程安全隐患的模块推倒重来的,可是改着改着就觉得不对劲了。

既然是返工,就想尽量把现在的理解完全加进去,让后面的人看了不要骂。可是想把几千行的代码改得面目全非并且更加安全准确也并不是一件容易的事,虽然对于功能和逻辑的认识比以前要清晰的多。

拿到一个新的模块,上面一般会给个大致的deadline。除非你对这个模块和整个项目的依赖关系(接口、逻辑、功能)有很好的把握,否则,你根本不知道到底有多少东西是已经实现的,有多少东西是可以复用的,有多少东西是需要修改的,有多少东西是要重写的,有多少东西是要新加的,仅仅根据需求预估的进度是不可能恰到好处的。而脱离了整个项目实现的模块是非常可能出问题的,尤其是在使用多线程的项目中。

当我的这个模块完成并上马之后,我沾沾自喜的跟上面说,应该是不会有问题了,上面跟我说了一句:如果不出问题就是奇迹了,我当时颇不以为然。在后面一两周之内真的就是没有什么问题,我真想告诉他是我创造了奇迹。

“奇迹”在2007年的最后一周破灭了。在我从西岭雪山回来的那天,为了增加新功能把代码修改了一些,结果第二天更新之后,服务器就老是有问题,找了一下午,才发现在修改代码的时候居然忘记对一个pointer做NULL判定!我心想,这种错误居然都出来了!死了算了!而且这个问题出在非主线程中。然后就和同事在考虑,这个东西如果线程同步出现问题,你就是每次使用前都做NULL判定也没用,所以就决定把这个模块重写了。

在这儿我就不想就线程安全问题多说了,以后想好了再专门去写点多线程的东西吧,今天只是想说点琐碎的东西。

因为是放假,心思未必就全部放在上面了,代码没改多少,倒是玩了很长时间的游戏。后来想想,也不全是时间问题,几千行的代码改来改去,难保不出现更多的问题。必须把它当作一个新的模块去写,先要把逻辑结构完全理出来,能多细化就多细化,最好能够精确到变量的使用,而且把文档做细,这样就可以在写文档的过程中把问题尽可能想全想清楚。改代码先改文档,这几乎是所有学过软件工程并写过项目的同学都能认识并理解的常识,可是在实际工作中,上有任务催赶,下有闲心杂念,很难把文档和注释写好。而做不到这一点的话,你就不敢保证你的模块不出差错。

所以,对于一个一般的需求,如果deadline是2个月的话。读需求、评估依赖关系、量进度要花掉1周,画逻辑结构、写文档要花掉3周,相当于前面一半的时间没有动手写代码,然后写代码大概只用1周,甚至更少,其他时间就留给测试和修改文档、代码了。从软件工程的角度,这样的分配是合理的,而且是应该的,但到了实际项目里面,又做不到!看来,不管是manager,还是coder,都不能急,软件工程不能白学了。

我发现,我的软件工程就是白学了,以后得改改。

/*****************************************************************************
 不想回头去动以前的代码,每次看以前写过的东西,都有一种想把它彻底删除的冲动。
 把需求看好、文档写好、时间安排好,这才是硬道理……

 毕竟是新年,还是祝大家:新年快乐!
 重要的是,新的一年,别荒废了……
*****************************************************************************/

posted @ 2008-01-02 02:43 Fox 阅读(765) | 评论 (6)编辑 收藏

Author: Fox

对于(1+2+...+N) 的求和,最早就是看高斯的故事,而且说实话,我是没有这样的智商的:

                sum(1+2+...+N) = N*(N+1)/2

刚看了一篇研究该级数求和的文章,虽为调侃,但实在感觉文中纰漏太多,不禁在此多言。

文中的第一种方法自称标准,而且还能使“全班2/3的同学都用俺的标准应付老师和试卷”,我大为惊诧:

1 int i, sum = 0 ;
2 for(i = 1;i < N;i ++)sum +=
 i;
3 printf("1-N的级数和是: %i",sum);


显然,printf的结果是N-1个数的和,此处,我更愿意相信是文中的笔误而已。

第二种和第三种方法让人觉得奇怪:

1 float  sum;
2 sum = (N ^ 2/ 2 + N / 2
;
3 printf("1-N的级数和是: %i",(int
)sum);
4 

5 float  sum;
6 sum = N * (N / 2 + 0.5
);
7 printf("1-N的级数和是: %i",(int)sum);


前面的写法纯属恶搞,^在C/C++中是异或位操作,相信接触过位运算的人都知道这一点,而且当N为奇数时,sum的结果将比真实值少1。后面的写法更是荒唐,当N为奇数时,sum的结果将比真实值相去更远(有兴趣的可以仔细看看)。

对于后面两种写法,我想说的重点不是这些明显的错误,因为这样的错误只可博众君一笑。但文中定义sum使用float的做法,让我百思不得其解。对于计算机的运算,浮点运算的耗时和整型运算的耗时,那不是一个数量级的。对于该级数运算,我们完全可以避免浮点运算,而且方法在文章一开始,就已经给出了:

1 int  sum;
2 sum = N*(N+1)/2
;
3 printf("1-N的级数和是: %i", sum);


无论N为奇数还是偶数,N*(N+1)一定是偶数,因此,上述方法不存在浮点运算,而且系统会自动将/2的操作优化为右移1位。

不知怎么,忽然就想到了递归,想到了Fibonacci数列。讲递归的教材都会拿上面的级数求和和Fibonacci数列做例子。其实,我个人感觉这是不恰当的,但想想为了让学生掌握递归算法,也只能举类似的简单的例子。我们也知道,递归计算对于堆栈调用是非常频繁而耗时的,对于求Hanoi塔这样的复杂问题,我不知道不用递归有没有更好的方法,但如果计算Fibonacci数列还是使用递归,在初学递归时是可以原谅的。简单点的方法可以是这样:

 1 int fib_odd = 0, fib_even = 1  ;
 2 int n = (N+1)/2
;
 3 for(int i=0; i<n; i++
 )
 4 
{
 5   fib_odd +=
  fib_even;
 6   fib_even +=
  fib_odd;
 7 
}
 8 int nFib = 0
;
 9 if( N % 2
 )
10   nFib =
 fib_odd;
11 else

12   nFib =  fib_even;
13 printf("Fibonacci数列前N项和是: %i",nFib); 


上面的两段代码中sum和nFib的值不能太大:)。

常言道,言过必失。但自私一点讲,把自己的错误暴露给别人,可以让自己更好的进步:),因此,我写下来,提醒自己也提醒大家,更欢迎大家多批评指正。

posted @ 2007-12-21 10:19 Fox 阅读(3343) | 评论 (10)编辑 收藏

Author: Fox

俗话说,道高一尺,魔高一丈。

今天在一个群里,有人提到某某算法(3DES)可以杜绝外挂。我当时心里苦笑一声:哥们儿,太逗了。这年头,中国人已经被忽悠怕了。我信鬼信魔,就是不信佛……

不过想想,如果能在一定程度上打击外挂,也不错,可是讨论了半天,愣是没有给出具体的方案,最后还是不了了之。

不过,有时间把思路整理整理,提一个稍微好一点的方法也好。

王城里面,一排排的外挂小号像阅兵一样,嚣张成马了,完全不把我们放在眼里。

话说回来,连个脱机外挂都防不住,别人还确实没必要把你放在眼里。

这边Login Server搞了两三个月的验证码,感觉不错,因为不使用外挂的玩家每次都要折腾半天,我们自己人员输入验证码输的都烦,结果没出半个月外挂又开始横行了,感觉比以前还嚣张。

我是外挂,我得意的笑,我得意的笑……

敢情是防贼没防住,把贼扔屋里,自己被锁在外面了!

/*****************************************************************************
  晚上本来想自己写个内挂,可以偷偷懒,可惜对这东西实在是从来没有过研究。
  折腾了一晚上,郁郁而终。
  技不如人啊!想来都觉得可笑……
*****************************************************************************/

posted @ 2007-12-20 02:08 Fox 阅读(2162) | 评论 (21)编辑 收藏

仅列出标题
共7页: 1 2 3 4 5 6 7