??xml version="1.0" encoding="utf-8" standalone="yes"?> 游戏的技能设计是增加游戏可玩性的重要方式之一?br />虽然在实际工作中Q大多遇到的情况应该是程序无法实现或者是因效率不够而放弃。但在一些网总?qing)单机游戏中Q技能枯燥的现象也屡见不鲜?br />本文借鉴于DOTA的技能设计说P探讨游戏中技能设计的思\与方向?br />技能可以暂时或者永q改变游戏中各种元素数倹{?br />q些元素几乎是构成游戏或者角色的基本元素比如HP.MP.力量、敏捗智力、{w速度、移动速度、视野、碰撞体U、天气、地形、等{?br />而所谓的技能就是可让玩家用之后短暂或者永久改变这些元素的东西?br />技能设计的味性也在此?br />一个技能所讑֮的元素可以直接媄(jing)响玩家的?j)态、或者说是用这个技能的U极性?br />如果游戏中出现几个、直到若q个无法引v玩家U极性的技能的话,那么׃(x)影响玩家Ҏ(gu)体游戏的U极性?br />而当我们设计技能的时候,p从迎合玩家的?j)态入手来设计游戏中的技能?br />下面只是整合出我暂时所能想到的元素Q排名不分优先程度?br /> 我们看一个实例:(x)
公司准备启动的一个手渔R目,服务器端准备使用|易的开源框架pomelo。pomelo是基于Node.js的高性能,分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组Ӟ库和工具包)(j)Q可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发?pomelo不但适用于游戏服务器开发, 也可用于开发高实时web应用Q它的分布式架构可以使pomelo比普通的实时web框架扩展性更好?br />
|易的架构师们选择?jin)node.js作ؓ(f)服务器端架构的核?j),说明了(jin)Node.js作ؓ(f)后端的Javascriptq行环境一定有它自q优越性?br />
提到JavascriptQ大安先想到的是日怋用的览器,C览器包含了(jin)各种lgQ包括渲染引擎、Javascript引擎{,其中Javascript引擎负责解释执行|页中的Javascript代码。作为Web前端最重要的语a之一QJavascript一直是前端工程师的专利。不q,Node.js是一个后端的Javascriptq行环境Q支持的pȝ包括Lnux、Windows、MacQ,q意味着你可以编写系l或者服务器端的Javascript代码Q交lNode.js来解释执行?br />
Node.js支持的语a是JavaScrpitQ之所以选择JavaScrpit作ؓ(f)服务器端q行语言理由如下Q?br />
1.Javascript作ؓ(f)前端工程师的d语言Q在技术社Z有相当的号召力。而且Q随着Web技术的不断发展Q特别是前端的重要性增加,不少前端工程师开始试?#8221;后台应用“Q在许多采用Node.js的企业中Q工E师都表C因Z(fn)惯了(jin)JavascriptQ所以选择Node.js?br />
2.Javascript的匿名函数和闭包Ҏ(gu)非帔R合事g驱动、异步编E,从helloworld例子中我们可以看到回调函数采用了(jin)匿名函数的Ş式来实现Q很方便。闭包的作用则更大,看下面的代码CZQ?br />
var hostRequest = http.request(requestOptions,function(response) {
var responseHTML ='';
response.on('data', function (chunk) {
responseHTML = responseHTML + chunk;
});
response.on('end',function(){
console.log(responseHTML);
// do something useful
});
});
3.Javascript在动态语a中性能较好Q有开发h员对Javacript、Python、Ruby{动态语a做了(jin)性能分析Q发现Javascript的性能要好于其他语aQ再加上V8引擎也是同类的佼D,所以Node.js的性能也受益其中?br />
JavaScript不仅在服务器端开始流行,在游戏客L(fng)~程斚w也成Z(jin)一个很重要的选择。就在不久前Q目前非常流行的一个手游引擎cocos2d-x也推Z(jin)JavaScript版本。引用创始h王哲的一句话Q如果说C++最靠谱的话Q那么Lua应该是最行Q而Javascript是最有前景?img src ="http://m.shnenglu.com/cxiaojia/aggbug/202240.html" width = "1" height = "1" />
]]>
1.视觉听觉的n受:(x)享受Q是的,是q样。玩家在玩游戏就是一Un受的q程Q满他的需要就?x)让他有享受的感觉。音乐与术Ҏ(gu)是最直接刺激直觉听觉Q媄(jing)响玩家心(j)情的元素?br />术Ҏ(gu)q不光是华丽越好,重要的是一定要做到W合技能的设计。如果技能是月神剑,Ҏ(gu)是个火焰形态的法球发出d不太协调?jin)。又好像是变形术Q如果你使用变Ş术之后仅仅是改变?sh)(jin)对方的模型大小的话Q也l对不会(x)有那U把别h变成动物的快感?jin)。而伴随着华丽的特效把敌h?yn)LQL?x)更加让人热血沸腾。这U效果当然还要配合适合的弹道以?qing)速度。。。等{?br />x(chng)不仅可以增加玩家的带入感Q还可以l游戏增加更多的味性。比如玩DOTA的时候,听到有h使用N步的声音Q而周围一个队友都没有。或者是在没有视野的地方Q却可以听到有h在练野的打斗声?br />ȝ来说x(chng)和音乐是最直观影响玩家?j)情的元素?br />2.多样性:(x)如果每个技能都是单一伤害Q或者仅仅是伤害以及(qing)常规的DEBUFF。那么也q当于同时降低?jin)游戏的可玩性。这里就需要组合各U元素的改变来创造出各种好玩的技能了(jin)?br />比如黑暗贤者的真空技能。就是整合了(jin)改变敌方坐标以及(qing)HP的元素、暗夜魔王可以通过改变天气来与自己的技能组合来增加自己的属性。幽g刃则是在造成伤害的同时还能改变地形属性。或者是末日守卫的死亡,增加?jin)数字判定的额外伤害。地I编l者的~地则是改变基础Ud速度、是否可见以?qing)碰撞之后受C害的整合
q些技能都是多样元素的重组Q多改变?sh)(jin)额外的元素Q则让游戏变得更加有׃性?br />沙王的穿刺(自己向前I刺Q对自己Ud路径中的敌h造成伤害眩晕Q同时瞬间改变自׃|。点d面施放)(j)
与老虎的蟩跃(向英雄模型的前方向蟩跃,跌q后增加X范围内友方单位的d速度与移动速度。)(j)
敌法的闪烁(点击地面施放Q蟩跃至该地点)(j)
qd(jing)刺客的突袭(指向性法术,点击一个目标蟩跃至目标的n边,q且增加下几ơ攻ȝd速度。)(j)
其中都是有相同的元素Q在之基上又增加?jin)其他元素的讑֮。这样即便是同类型的效果Q也可以通过不同的方式实现?br />利用各种元素的组合就可以创造出各种形态各异的技能。游戏的׃性亦是在此?br />3.实用性与q性:(x)一个音效与Ҏ(gu)非常炫目Qƈ且让人感觉很有意思的技能还需要一个让玩家频繁使用的要素。就是实用性。维持各个技能与英雄搭配之间的^衡,才能让技能变得有实用性。所以把实用性与q性放在了(jin)一赗也怽?x)发C些游戏中有不具备实用性的技能,仅仅凭借着华丽的特效而存在。但q种技能也只会(x)是一点点。。。没多少玩家愿意喜欢一个只有华而不实的技能的英雄的。击败其他玩家永q是大多数玩家最大的q求?br />
之后惌的一些,是怎样通过改变游戏元素的各U组合来创造出多样性技能的思\?br />你还?sh)知道怎样讑֮技能?那就再次举例。。?br />你可以把增加敌h单体Ud速度、攻击速度与增加自己攻击速度、移动速度l合h。这样就是死灵飞龙的黄泉之\?jin)?br />你可以把矩ŞAOE伤害Q与眩晕效果与地形改变组合。那样就变成?jin)牛牛的沟壑?br />你可以设定一个AOE技能,对范围内的目标造成伤害Q此时多加一个判定,是Ҏ(gu)?的倍数的造成额外的伤実뀂这样就是一个AOE与末日守卫技能的l合?jin)?br />你想增加一个RP性质极强的技能?L(fng)骑士的C与圣骑士的T不就是么Q还x(chng)加RP一点?
把死亡一指的伤害X1.5Q范围施?#8212;—对范围内的随Z个敌方单位造成伤害。这样不RP?jin)?br />游戏中技能的l合?x)更多的增加游戏的娱乐性,正是因ؓ(f)各种l合Q所以DOTA?5个英雄都能大攑օ彩?br />技能怎样ȝ合?也许DOTA中技能与技能元素直接互相媄(jing)响的英雄q不是非常多Q但是亦都有联系。下面就来设定一个新的英雄?br />我们先定义这个英雄的定位。他是一个力量型的英雄,q且有一定的q击与逃跑能力Q懂得保护自己和增加Ҏ(gu)所受到的伤実뀂而他需要用怎样的技能来表现他的定位呢?
增加Ud速度与攻击速度的技能,是最适合q击与逃跑的,但是太过单调。减免伤害与增加敌方单位受到的伤害都是已l有cM的技能了(jin)的。如何来讑֮一个具备这些条件而又与以往不同的英雄技能呢Q?br />减免伤害的方式有多种Q增加自q护甲Q或者直接减受C害的具体数|以及(qing)直接减免受到伤害的百分比{等很多方式。。?br />增加敌方受到伤害的方式亦有很多种Q比如DEBUFFQ让敌h受到额外的伤宻I可以直接的,单次的,或者是像苑一L(fng)累一定时间的?br />下面我们所想的是用怎样的技能把两种方式l合h?br />技?Q增加移动与d速度Q这个就是基Q但是不能光靠这个技能去表现。需要让其他的技能也可以实现q击与逃跑
技?Q挟持对方英雄,英雄紧脓(chung)着敌方英雄单位Q无法进行攻MUdQ在q之间受到的所有伤害都?x){到敌方英雄n上。这样就满?jin)英雄设定中所有的要求。但是这栯定有一定的问题Q就是挟持之后,敌方玩家都不再攻击被挟持的单位。且挟持对友方单位的dq没有增q的作用。这L(fng)技能还是缺乏一些实用性。这样就出现?jin)技?.
技?Q永久性被动技能,减少被挟持英雄的Ud速度。如果仅仅是q样的话Q那么依旧ƈ不是多样化。于是又增加?jin)可切换的功能。姿?是减自׃?qing)自己所挟持目标所受到的所有伤宻I姿?是增加自׃?qing)自己所挟持目标的所有伤実뀂这样亦是通过原来DOTA没有的方式完成了(jin)减免伤害与增加对Ҏ(gu)受到伤害的方式?br />q样一个徏议的新英雄概念就出来?jin)。。。之后就是具体设定的调整Q比如被挟持的单位是处于什么状态,以及(qing)具体数值的讑֮{等。。?br />
MQ技能的讑֮是多样化的,多到思\永远不会(x)被局限。永q都可以有更多更有意思的技能被讑֮出来?br />此文只是写的一些技能设定的思\Q没有考虑M实现问题。。。此斚wq是不要拍我?jin)?br />惛_l一些苦g不知道怎样讑֮好玩的技能的新手。。。希望对他们有一点点帮助?/span>
]]>
把这两天做Proactor的一些经验和?j)得写一下,可能?x)给一些h帮助?br /> Proactor是异步模式的|络处理器,ACE中叫?#8220;前摄?#8221;?br /> 先讲几个概念Q?br /> 前摄器(ProactorQ-异步的事件多路分d、处理器Q是核心(j)处理cR启动后?个线E组成(你不需要关?j)这三个U程Q我只是让你知道一下有q回事存在)(j)?br /> 接受器(AcceptorQ-用于服务端,监听在一个端口上Q接受用L(fng)h?br /> q接器(ConnectorQ-用于客户端,去连接远E的监听。当?dng)如果q程是ACE写的Q就是Acceptor?br /> 异步模式Q即非阻塞模式。网l的传输速度一般来讲ؓ(f)10Mbps?00Mbps?000Mbps。拿千兆|来_(d)实际的传输速度?000Mbps/8大概?28KB左右。我们的CPU一般ؓ(f)P4 3.0GHZQ如果是32位的处理器,一U钟大概可以处理6G的字节,那么Q?28KB的网l速度是远q及(qing)不上处理器的速度的。网l发送数据是一位一位发送出ȝQ如果CPU{在q里Q发送完成函数才l束Q那么,处理器浪费了(jin)大量旉在网l传输上?br /> 操作pȝ提供?jin)异步的模式来传输网l数据,工作模式卻I(x)应用E序把要发送的数据交给操作pȝQ操作系l把数据攑֜pȝ~冲区后告诉应用程序OK?jin),我帮你发Q应用程序该q嘛q嘛厅R操作系l发送完成后Q会(x)l应用系l一个回执,告诉应用E序Q刚才那个包发送完成了(jin)Q?br /> 举个例子Q你有几邮件和包裹要发Q最有效率的办法是什么?你把邮g和包裹及(qing)交给dQdMM_(d)好了(jin)Q你帮你发,你忙dQ然后你d作了(jin)。过?jin)一?x),dMM打电(sh)话告诉你Q?#8220;刚才我叫快递公司的人来?jin),把你的包裹发出去了(jin)。邮局的h也来?jin),取走了(jin)邮Ӟ攑ֿ?j)好了(jin)”。同P如果你知道今天会(x)有包Ҏ(gu)Q比如你在淘宝上购物?jin),你能成天{在dQ你应该告诉dMMQ?#8220;今天可能有我的一个快递,你帮我收一下,晚上请你肯d基!”。MMQ?#8220;看在肯得基的面子上,帮你收了(jin)”。某个时_(d)MM打电(sh)话来?jin)?x)“帅哥Q你的包裹到?jin),我帮你签收?jin)Q快来拿吧?#8221;
因ؓ(f)操作pȝ是很有效率的Q所有,他在后台收发是很快的。应用程序也很简单。Proactor是q种异步模式的。Proactor是dMMQACE_Service_Handle是d代ؓ(f)收发邮g的公司流E?/p>
//***********************************************************
class TPTCPAsynchServerImpl : public ACE_Service_Handler
{
public:
TPTCPAsynchServerImpl(void);
~TPTCPAsynchServerImpl(void);
virtual void open (ACE_HANDLE handle, ACE_Message_Block &message_block);
virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
virtual void handle_time_out (const ACE_Time_Value &tv, const void *act=0);
private:
int initiate_read_stream (const ACE_Asynch_Read_Stream::Result &result);
ACE_Asynch_Read_Stream rs_;
ACE_Asynch_Write_Stream ws_;
};
q个例子从ACE_Service_Handlerl承q来QACE_Service_Handle主要是定义?jin)一些回调函数?br />1?virtual void open (ACE_HANDLE handle, ACE_Message_Block &message_block);
当有客户端连接上来,q接建立成功后Proactor?x)调用这个方法?/p>
2?virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
当用戯ȝ数据d?jin)后Q调用这个方?/p>
3、virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
当用戯写的数据在网卡上发送成功后QProactor?x)回调这个方?/p>
4?virtual void handle_time_out (const ACE_Time_Value &tv, const void *act=0);
当用戯定的旉到期?jin),q个Ҏ(gu)?x)被调用?/p>
q跟和dMM的联l方法是不是一L(fng)Q?/p>
对还~点东西Q缺怎么向dMM交待d的方法。下面看看:(x)
首先Q创Z个监听器?/p>
ACE_Asynch_Acceptor<TPTCPAsynchServerImpl> acceptor_;
看到没,是我们刚才写的c,因ؓ(f)他承了(jin)回调接口Qƈ实现?jin)自已的代码Q模板中ACE_Asynch_Acceptor?x)在合适的时候回调这些方法?/p>
//创徏一个地址对象
ACE_INET_Addr addr(port, ip);
acceptor_.open (addr, 8 * 1024, 1);
Open后,开始监听了(jin)。其它的Q向Proactor注册一些事件的事模板类中都替你做了(jin)Q你不需要做很多事?br /> 那么Q已l开始监听了(jin)Q我的程序从哪里开始呢Q对于一个服务程序来ԌE序是被用户的连接驱动的Q一个用L(fng)序想和通讯Q必d创徏q接Q就是Socket中的connect操作。这个操作Proactor?x)替我们做一些工作,当连接创建完成后Q上面讲的OpenҎ(gu)?x)被调用Q我们看看OpenҎ(gu)中都有些什么代码:(x)
我们看到Q首先创Z(jin)两个,是前面cd义中定义的一个异步写,一个异步读。以后对|络的读和写通过q两个流q行。我q给Z(jin)一D读客户端地址和端口的代码。然后是d客户Connect可能附带的数据,那段代码不用看懂Q以后用照抄就行。然后就?/p>
q段代码使用LMD|据。这D代码就是向dMM交待Q我要收包裹Q收好了(jin)叫我Q?br />也就是说Q这D代?9%的可能是M出数据的Q只是向Proactor注册ȝ事gQ具体的{待、读取操作由P(pn)roactor读,d?jin),回调Handle_Read_StreamҎ(gu)。ACE_Message_Block是消息块Q数据就是存攑֜消息块中的?br />下面看看Handle_Read_StreamҎ(gu)的代码:(x)
q个函数被调用,p明有数据已经d?jin),包裹已经在d?jin)。Proactor比dMMq好Q给你送上门了(jin)Q数据就在Result里,上面演示?jin)Result中的数据。然后把消息块释放了(jin)Q然后调用initiate_read_streaml箋(hu)监听|络上可能到来的数据。看看initiate_read_stream好了(jin)Q?/p>
代码很简单,是创徏一个新的消息块Q然后用读注册一个读消息可以了(jin)?/p>
到此为止QProactor的读程很清楚了(jin)吧?
下面再说一个写程?/p>
写流E其实更单,在Q意想向客L(fng)写数据的地方Q调用相应代码就行了(jin)Q比如,我们提供?jin)SendDataҎ(gu)来发送数据,在Q意想发送数据的地方调用SendDatap?jin),SendData的代码如下:(x)
单说Q就是创Z(jin)一个消息块Q把用户数据拯q来Q然后调用写WS向Proactor发送一个Write事g可以了(jin)Q发送成功后QHandle_write_handle?x)被调用Q看一下:(x)
代码中用了(jin)result中发数据Q然后把消息块释放了(jin)Q就q么单?/p>
////////////////////////////////////////////////////////////////////////////////////////////////////
q是单的proactor用法Q当?dng)复杂也基本就q样用。所谓不基本的不是Proactor的内容,而是服务器编E本w的ȝ(ch)。比如说Q多个连接的理、重发机制、发送队列等{,q都不是ACE的内宏V这些要大家自己思考了(jin)Qƈd?/p>
在这里,我要说几个重要的问题Q连接的理。Acceptor是一个类Q但是在每一个连接,Proactor都用?jin)某U办法创Z(jin)一个实例,所以,q接理的群集类一定不能在AcceptorcMQ不然得到的l果是始终只有一条记录。因为每个Acceptor都有一个实例,实例对应一个连接,集cM每个实例一个了(jin)。要采取的方法是一个全局的容器对象就可以?jin)。比如我q个c:(x)
我用ACE的Singleton模板创徏q个c,每一个Acceptor要用ConnectionMapQ都使用q里的_connectionsQ方法如?Q?br /> GlobleSingleton::instance()->connection.bind()......
q个问题可是我花费了(jin)2天时间找出来的,怽同仁不可不戒啊,l点掌声Q)(j)
好处
转自Q?a >http://blog.csdn.net/hguisu/article/details/7453390
1. 概念理解
在进行网l编E时Q我们常常见?span style="margin: 0px; padding: 0px; font-family: Arial, Helvetica, sans-serif, ?hu)? font-size: 12px; line-height: 16px; text-indent: 24px;">同步(Sync)/异步(Async)Q阻?Block)/非阻?Unblock)四种调用方式Q?/span>
同步Q?/span>
所谓同步,是在发Z个功能调用时Q在没有得到l果之前Q该调用׃q回?/span>也就是必M件一件事?/strong>,{前一件做完了(jin)才能做下一件事?/span>
例如普?span style="margin: 0px; padding: 0px; font-family: 'Times New Roman';">B/S模式Q同步)(j)Q提交请?span style="margin: 0px; padding: 0px; font-family: 'Times New Roman';">->{待服务器处?span style="margin: 0px; padding: 0px; font-family: 'Times New Roman';">->处理完毕q回 q个期间客户端浏览器不能qQ何事
异步Q?/span>
异步的概念和同步相对。当一个异步过E调用发出后Q调用者不能立d到结果。实际处理这个调用的部g在完成后Q通过状态、通知和回调来通知调用者?/span>
例如 ajaxhQ?/span>异步Q?/span>: h通过事g触发->服务器处理(q是览器仍然可以作其他事情Q?/span>->处理完毕
d
d调用是指调用l果q回之前Q当前线E会(x)被挂PU程q入非可执行状态,在这个状态下Qcpu不会(x)l线E分配时间片Q即U程暂停q行Q。函数只有在得到l果之后才会(x)q回?/span>
有h也许?x)把d调用和同步调用等同v来,实际上他是不同的。对于同步调用来_(d)很多时候当前线E还是激zȝQ只是从逻辑上当前函数没有返回而已?/span> 例如Q我们在socket中调用recv函数Q如果缓冲区中没有数据,q个函数׃(x)一直等待,直到有数据才q回。而此Ӟ当前U程q(sh)(x)l箋(hu)处理各种各样的消息?/span>
非阻?/strong>
非阻塞和d的概늛对应Q指在不能立d到结果之前,该函C?x)阻塞当前线E,而会(x)立刻q回?/span>
对象的阻塞模式和d函数调用
对象是否处于d模式和函数是不是d调用有很强的相关性,但是q不是一一对应的。阻塞对象上可以有非d的调用方式,我们可以通过一定的API去轮询状 态,在适当的时候调用阻塞函敎ͼ可以避免阻塞。而对于非d对象Q调用特D的函数也可以进入阻塞调用。函?/span>select是q样的一个例子?/span>
1. 同步Q就是我调用一个功能,该功能没有结束前Q我ȝl果?/span>
2. 异步Q就?span style="margin: 0px; padding: 0px; line-height: 20px;">我调用一个功能,不需要知道该功能l果Q该功能有结果后通知我(回调通知Q?/span>
3. dQ? 是调用我(函数Q,?span style="margin: 0px; padding: 0px; line-height: 20px;">Q函敎ͼ(j)没有接收完数据或者没有得到结果之前,我不?x)返回?/span>
4. 非阻塞, 是调用?span style="margin: 0px; padding: 0px; line-height: 20px;">Q函敎ͼ(j)Q我Q函敎ͼ(j)立即q回Q?span style="margin: 0px; padding: 0px; line-height: 20px;">通过select通知调用?/span>
同步IO和异步IO的区别就在于Q?span style="margin: 0px; padding: 0px; color: #ff0000;">数据拯的时候进E是否阻塞!
dIO和非dIO的区别就在于Q?/span>应用E序的调用是否立卌回!
对于举个单c/s 模式Q?/span>
同步和异?d和非d,有些L(fng),其实它们完全不是一回事,而且它们修饰的对象也不相同?br style="margin: 0px; padding: 0px;" />d和非d是指当进E访问的数据如果未qA,q程是否需要等?单说q相当于函数内部的实现区?/span>,也就是未qA时是直接q回q是{待qA;
而同步和异步?/span>指访问数据的机制,同步一般指dhq等待I/O操作完毕的方?当数据就l后在读写的时候必阻?区别qA与读写二个阶D?同步的读写必阻?,异步则指dh数据后便可以l箋(hu)处理其它d,随后{待I/O,操作完毕的通知,q可以ɘq程在数据读写时也不d?{待"通知")
1. Linux下的五种I/O模型
1)dI/OQblocking I/OQ?br style="margin: 0px; padding: 0px;" />2)非阻塞I/O Qnonblocking I/OQ?/span>
3) I/O复用(select 和poll) QI/O multiplexingQ?/span>
4)信号驱动I/O Qsignal driven I/O (SIGIO)Q?/span>
5)异步I/O Qasynchronous I/O (the POSIX aio_functions)Q?/span>
前四U都是同步,只有最后一U才是异步IO?/p>
介:(x)q程?/span>一直阻?/span>Q直到数据拷贝完?/span>
应用E序调用一个IO函数Q导致应用程序阻塞,{待数据准备好?如果数据没有准备好,一直等?#8230;.数据准备好了(jin)Q从内核拯到用L(fng)?IO函数q回成功指示?/span>
dI/O模型图:(x)在调用recv()/recvfromQ)(j)函数Ӟ发生在内怸{待数据和复制数据的q程?/span>
当调用recv()函数Ӟpȝ首先查是否有准备好的数据。如果数据没有准备好Q那么系l就处于{待状态。当数据准备好后Q将数据从系l缓冲区复制到用L(fng)_(d)然后该函数返回。在套接应用E序中,当调用recv()函数Ӟ未必用户I间已l存在数据,那么此时recv()函数׃(x)处于{待状态?br style="margin: 0px; padding: 0px;" />
当用socket()函数和W(xu)SASocket()函数创徏套接字时Q默认的套接字都是阻塞的。这意味着当调用Windows Sockets API不能立即完成ӞU程处于{待状态,直到操作完成?/span>
q不是所有Windows Sockets API以阻塞套接字为参数调用都?x)发生阻塞。例如,以阻塞模式的套接字ؓ(f)参数调用bind()、listen()函数Ӟ函数?x)立卌回。将可能d套接字的Windows Sockets API调用分ؓ(f)以下四种:
1Q输入操作:(x) recv()、recvfrom()、WSARecv()和W(xu)SARecvfrom()函数。以d套接字ؓ(f)参数调用该函数接收数据。如果此时套接字~冲区内没有数据可读Q则调用U程在数据到来前一直睡眠?/span>
2Q输出操作:(x) send()、sendto()、WSASend()和W(xu)SASendto()函数。以d套接字ؓ(f)参数调用该函数发送数据。如果套接字~冲区没有可用空_(d)U程?x)一直睡眠,直到有空间?/span>
3Q接受连接:(x)accept()和W(xu)SAAcept()函数。以d套接字ؓ(f)参数调用该函敎ͼ{待接受Ҏ(gu)的连接请求。如果此时没有连接请求,U程׃(x)q入睡眠状态?/span>
4Q外?gu)接?x)connect()和W(xu)SAConnect()函数。对于TCPq接Q客L(fng)以阻塞套接字为参敎ͼ调用该函数向服务器发赯接。该函数在收到服务器的应{前Q不?x)返回。这意味着TCPq接M(x){待臛_到服务器的一ơ往q时间?/span>
使用d模式的套接字Q开发网l程序比较简单,Ҏ(gu)实现。当希望能够立即发送和接收数据Q且处理的套接字数量比较?yu)的情况下,使用d模式来开发网l程序比较合适?/span>
d模式套接字的不表现为,在大量徏立好的套接字U程之间q行通信时比较困难。当使用“生?消费?#8221;模型开发网l程序时Qؓ(f)每个套接字都分别分配一个读U程、一个处理数据线E和一个用于同步的事gQ那么这h疑加大系l的开销。其最大的~点是当希望同时处理大量套接字时Q将无从下手Q其扩展性很?/span>
我们把一个SOCKET接口讄为非d是告诉内核Q当所h的I/O操作无法完成Ӟ不要进E睡眠,而是q回一个错误。这h们的I/O操作函数不断的试数据是否已经准备好,如果没有准备好,l箋(hu)试Q直到数据准备好为止。在q个不断试的过E中Q会(x)大量的占用CPU的时间?/span>
?span style="margin: 0px; padding: 0px; font-size: 14px;">SOCKET讄为非d模式Q即通知pȝ内核Q在调用Windows Sockets APIӞ不要让线E睡眠,而应该让函数立即q回。在q回Ӟ该函数返回一个错误代码。图所C,一个非d模式套接字多ơ调用recv()函数的过E。前三次调用recv()函数Ӟ内核数据q没有准备好。因此,该函数立卌回WSAEWOULDBLOCK错误代码。第四次调用recv()函数Ӟ数据已经准备好,被复制到应用E序的缓冲区中,recv()函数q回成功指示Q应用程序开始处理数据?/span>
当用socket()函数和W(xu)SASocket()函数创徏套接字时Q默认都是阻塞的。在创徏套接字之后,通过调用ioctlsocket()函数Q将该套接字讄为非d模式。Linux下的函数?fcntl().
套接字设|ؓ(f)非阻塞模式后Q在调用Windows Sockets API函数Ӟ调用函数?x)立卌回。大多数情况下,q些函数调用都会(x)调用“p|”Qƈq回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有旉完成。通常Q应用程序需要重复调用该函数Q直到获得成功返回代码?/span>
需要说明的是ƈ非所有的Windows Sockets API在非d模式下调用,都会(x)q回WSAEWOULDBLOCK错误。例如,以非d模式的套接字为参数调用bind()函数Ӟ׃?x)返回该错误代码。当?dng)在调用WSAStartup()函数时更不会(x)q回该错误代码,因ؓ(f)该函数是应用E序W一调用的函敎ͼ当然不会(x)q回q样的错误代码?/span>
要将套接字设|ؓ(f)非阻塞模式,除了(jin)使用ioctlsocket()函数之外Q还可以使用WSAAsyncselect()和W(xu)SAEventselect()函数。当调用该函数时Q套接字?x)自动地讄为非d方式?br style="margin: 0px; padding: 0px;" />
׃使用非阻塞套接字在调用函数时Q会(x)l常q回WSAEWOULDBLOCK错误。所以在M时候,都应仔细(g)查返回代码ƈ作好?#8220;p|”的准备。应用程序连l不断地调用q个函数Q直到它q回成功指示为止。上面的E序清单中,在While循环体内不断地调用recv()函数Q以d1024个字节的数据。这U做法很费pȝ资源?/span>
要完成这L(fng)操作Q有Z用MSG_PEEK标志调用recv()函数查看~冲Z是否有数据可诅R同Pq种Ҏ(gu)也不好。因做法对系l造成的开销是很大的Qƈ且应用程序至要调用recv()函数两次Q才能实际地d数据。较好的做法是,使用套接字的“I/O模型”来判断非d套接字是否可d写?/span>
非阻塞模式套接字与阻塞模式套接字相比Q不Ҏ(gu)使用。用非d模式套接字,需要编写更多的代码Q以便在每个Windows Sockets API函数调用中,Ҏ(gu)到的WSAEWOULDBLOCK错误q行处理。因此,非阻塞套接字便显得有些难于用?/span>
但是Q非d套接字在控制建立的多个连接,在数据的收发量不均,旉不定Ӟ明显h优势。这U套接字在用上存在一定难度,但只要排除了(jin)q些困难Q它在功能上q是非常强大的。通常情况下,可考虑使用套接字的“I/O模型”Q它有助于应用程序通过异步方式Q同时对一个或多个套接字的通信加以理?/span>
介:(x)主要是select和epollQ对一个IO端口Q两ơ调用,两次q回Q比dIOq没有什么优性;关键是能实现同时对多个IO端口q行监听Q?/span>
I/O复用模型?x)用到select、poll、epoll函数Q这几个函数也会(x)使进E阻塞,但是和阻塞I/O所不同的的Q这两个函数可以同时d多个I/O操作。而且可以同时对多个读操作Q多个写操作的I/O函数q行(g),直到有数据可L可写Ӟ才真正调用I/O操作函数?/span>
介:(x)两次调用Q两ơ返回;
首先我们允许套接口进行信号驱动I/O,q安装一个信号处理函敎ͼq程l箋(hu)q行q不d。当数据准备好时Q进E会(x)收到一个SIGIO信号Q可以在信号处理函数中调用I/O操作函数处理数据?/span>
介:(x)数据拯的时候进E无需d?/span>
当一个异步过E调用发出后Q调用者不能立d到结果。实际处理这个调用的部g在完成后Q通过状态、通知和回调来通知调用者的输入输出操作
同步IO引vq程dQ直至IO操作完成?br style="margin: 0px; padding: 0px;" />异步IO不会(x)引vq程d?br style="margin: 0px; padding: 0px;" />IO复用是先通过select调用d?br style="margin: 0px; padding: 0px;" />
1. select、poll、epoll?br style="margin: 0px; padding: 0px;" />
epoll跟select都能提供多\I/O复用的解x(chng)案。在现在的Linux内核里有都能够支持,其中epoll是Linux所Ҏ(gu)Q而select则应该是POSIX所规定Q一般操作系l均有实?/p>
selectQ?/span>
select本质上是通过讄或者检查存放fd标志位的数据l构来进行下一步处理。这h带来的缺Ҏ(gu)Q?/p>
1?单个q程可监视的fd数量被限Ӟ卌监听端口的大有限?br style="margin: 0px; padding: 0px;" />
一般来说这个数目和pȝ内存关系很大Q具体数目可以cat /proc/sys/fs/file-max察看?2位机默认?024个?4位机默认?048.
2?对socketq行扫描时是U性扫描,即采用轮询的Ҏ(gu)Q效率较低:(x)
当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调?不管哪个Socket是活跃的,都遍历一遍。这?x)浪费很多CPU旉。如果能l套接字注册某个回调函数Q当他们z跃Ӟ自动完成相关操作Q那避免了(jin)轮询Q这正是epoll与kqueue做的?/p>
3、需要维护一个用来存攑֤量fd的数据结构,q样?x)得用L(fng)间和内核I间在传递该l构时复制开销?/p>
pollQ?/span>
poll本质上和select没有区别Q它?yu)用户传入的数组拯到内核空_(d)然后查询每个fd对应的设备状态,如果讑֤qA则在讑֤{待队列中加入一ƈl箋(hu)遍历Q如果遍历完所有fd后没有发现就l设备,则挂起当前进E,直到讑֤qA或者主动超Ӟ被唤醒后它又要再ơ遍历fd。这个过E经历了(jin)多次无谓的遍历?/p>
它没有最大连接数的限Ӟ原因是它是基于链表来存储的,但是同样有一个缺点:(x)
1、大量的fd的数l被整体复制于用h和内核地址I间之间Q而不这L(fng)复制是不是有意义?nbsp; 2、pollq有一个特Ҏ(gu)“水^触发”Q如果报告了(jin)fd后,没有被处理,那么下次poll时会(x)再次报告该fd?/p>epoll:
epoll支持水^触发和边~触发,最大的特点在于边缘触发Q它只告诉进E哪些fd刚刚变(sh)ؓ(f)需态,q且只会(x)通知一ơ。还有一个特Ҏ(gu)Qepoll使用“事g”的就l通知方式Q通过epoll_ctl注册fdQ一旦该fdqAQ内核就?x)采用类似callback的回调机制来Ȁz该fdQepoll_wait便可以收到通知
epoll的优点:(x)
1、支持一个进E所能打开的最大连接数
select | 单个q程所能打开的最大连接数有FD_SETSIZE宏定义,其大是32个整数的大小Q在32位的机器上,大小是32*32Q同?4位机器上FD_SETSIZE?2*64Q,当然我们可以对进行修改,然后重新~译内核Q但是性能可能?x)受到?jing)响,q需要进一步的试?/p> |
poll | poll本质上和select没有区别Q但是它没有最大连接数的限Ӟ原因是它是基于链表来存储?/p> |
epoll | 虽然q接数有上限Q但是很大,1G内存的机器上可以打开10万左右的q接Q?G内存的机器可以打开20万左右的q接 |
2、FD剧增后带来的IO效率问题
select | 因ؓ(f)每次调用旉?x)对q接q行U性遍历,所以随着FD的增加会(x)造成遍历速度慢的“U性下降性能问题”?/p> |
poll | 同上 |
epoll | 因ؓ(f)epoll内核中实现是Ҏ(gu)每个fd上的callback函数来实现的Q只有活跃的socket才会(x)d调用callbackQ所以在z跃socket较少的情况下Q用epoll没有前面两者的U性下降的性能问题Q但是所有socket都很z跃的情况下Q可能会(x)有性能问题?/p> |
3?消息传递方?/p>
select | 内核需要将消息传递到用户I间Q都需要内核拷贝动?/p> |
poll | 同上 |
epoll | epoll通过内核和用L(fng)间共享一块内存来实现的?/p> |
ȝQ?/span>
lgQ在选择selectQpollQepoll时要Ҏ(gu)具体的用场合以?qing)这三种方式的自w特炏V?/p>
1、表面上看epoll的性能最好,但是在连接数ƈ且连接都十分z跃的情况下Qselect和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调?/p>
2?span style="margin: 0px; padding: 0px; color: #000000; background-color: #ffcc00;">select低效是因为每ơ它都需要轮询。但低效也是相对的,视情况而定Q也可通过良好的设计改?/span>
2CArchiveCArchive允许以一个永久二q制Q通常为磁盘存储)(j)的Ş式保存(sh)个对象的复杂|络Q它可以在对象被删除Ӟq能怹保存。可以从怹存储中装载对象,在内存(sh)重新构造它们。得数据永久保留的q程叫?/span>“序列?#8221;//ASCII3CArchive 4对象处理自定义对象类型数?/strong> 3DECLARE_SERIALIMPLEMENT_SERIAL4在Serialize成员函数中完成保存和加蝲的功能?/p>
DECLARE_SERIAL( class_name ) IMPLEMENT_SERIAL( class_name, base_class_name, wSchema ) W一个参Cؓ(f)当前cdQ第二个参数为父cȝ名,W三个参Cؓ(f)该类的特定整型标?span style="font-family: 'Times New Roman'">,()Q最ؓ(f)0CZQ?/p>
重蝲提取Q?span style="font-family: 'Times New Roman'">>> ?span style="font-family: 'Times New Roman'">MFC 完成之后Q点击菜单栏上的保存和打开可以实现序列化?jin)?/p>
必须在创Z?span style="font-family: 'Times New Roman'">CArchiveCFile/CArchiveCFileCZQ?/p>
CFile file("1.txt",CFile::modeCreate | CFile::modeWrite); //定义一个文件流对象
CArchive ar(&file,CArchive::store); //定义一个序列化对象和文件流对象l定q指定归档方式ؓ(f)储存Q加载的方式为CArchive::load
int i=4;
char ch='a';
float f=1.3f;
CString str("aa");
ar<<i<<ch<<f<<str; //储存到文?/span>
CArchive1zcR?/span>直接或者间接的l承CObject2、必重写C(j)ObjectcȝSerialize成员函数?/p>
//DrawBase.h
class CDrawBase : public CObject //l承自CObject
{
public:
DECLARE_SERIAL(CDrawBase) //W一个宏的位|,参数为当前类?/span>
CDrawBase();//必须有一个默认构造函?/span>
virtual void onDraw(CDC* pdc);
virtual ~CDrawBase();
public:
UINT m_PenStyle;
int m_PenWidth;
int m_BkMode;
int m_BrushStyle;
int m_issx;
int m_isyy;
COLORREF m_PenColor;
COLORREF m_BackgroundColor;
COLORREF m_BrushColor;
CPoint m_ptBegin;
CPoint m_ptEnd;
public:
void Serialize(CArchive& ar);//重写?jin)Serialize成员函数
};
//DrawBase.cpp
IMPLEMENT_SERIAL(CDrawBase, CObject, 1) //W二个宏的位|,W一个参Cؓ(f)当前cdQ第二个参数为父cȝ名,W三个参Cؓ(f)该类的特定整型标?该标识将用来解序(重新实例?Q最ؓ(f)0
void CDrawBase::Serialize(CArchive& ar)
{
CObject::Serialize(ar);
if(ar.IsStoring())//保存Q加载ؓ(f)ar.IsLoading()
{
ar <<m_PenColor<<m_PenStyle<<m_PenWidth<<m_BrushColor<<m_BrushStyle<<m_issx<<m_isyy;
}
Else //加蝲
{
ar >>m_PenColor>>m_PenStyle>>m_PenWidth>>m_BrushColor>>m_BrushStyle>>m_issx>>m_isyy;
}
}
]]>
1. NoSQL其实是关pd数据库相对应的,是no relational 即非关系型数据库Qweb2.0特别是一些用戯问量比较大的|站如:(x)www.taobao.com weibo.com baidu.com
每秒的访问量可能是上万次(10K);传统的关pd数据?mysql oracle 每秒q行10Kơ数据查询还可以勉强应付Q但是如果是每秒10Kơ读写数据库Q因为数据库的数据都是卸载磁盘(sh)Q所以磁盘I(y)O也是支撑不住每秒10K的读写?/p>
在web的架构中Q数据库是最难进行横向扩展的(通过单的d机器和硬Ӟ也就是添加一些服务节Ҏ(gu)提高负蝲均衡能力)Q对?*24时在线的网站来_(d)对关pd数据库进行升U和扩展(分布式扩?-分库分表)是非常痛苦的事情Q往往要进行停机维护;但这U对www.taobao.com 来说是非怸陋的事情。[--可不可以d几台服务器然后把复制Q然后进行负载均?-]?/p>
NoSQL 是采用key/value的结构来存储数据Q而且大多数的NoSQL采用内存来存储数据,一D|间后把数据同步到盘?sh);׃使?strong>内存?sh)?/strong>数据很好地解决了(jin)高ƈ发读?/strong>的问题;其次NoSQL提供?jin)根据keyD行横向分?比如Q用户idQ每2000w数据攑ֈ一台数据库服务器中的一张用戯?Q同时实C(jin)M数据库互备,q样可以让数据库的动态迁Ud得简单,让数据库服务器的横向扩展变得Ҏ(gu)?jin)?/p> 2. 分布式数据库的CAP理论 CAP理论是说ConsistencyQ一致性)(j)Q?/span> AvailabilityQ可用性)(j)Q?/span> partition toleranceQ分布)(j)三部分系l;而且Mpȝ只会(x)满两个Q不?x)有M的系l会(x)同时满q三个条Ӟ在传l的关系型数据库中是C 一致性,但是在满高可用?高ƈ发时效率不高)Q高扩展?分布式数据库q行横向扩展)存在一定的~陷。但是NoSQL在进行设计的时候就是针对ƈ发v量数据存储的情况下进行设计的Q在q种高ƈ发v量数据下数据一致性ƈ不像银行那样保持数据的强一致性,所以NoSQL·攑ּZ致性的q求Q从而达到更高的可用性和扩展性,通过“鸽l(f)原理”辑ֈ最l的一致性?/span> 现在的数据库pȝ肯定是同一个时L多个q程Ҏ(gu)据库q行d操作Q假讄在有3个进E?A、B、C)Ҏ(gu)据库的某表进行操作, 解决Ҏ(gu)Q?/span> 1Q?/font> 打开开始菜单,点击q行按钮Q输?/span>regeditQ进入注册表界面 2Q?/font> 扑ֈ目录 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones 3Q?/font> 查看此目录下是否存在1000目录Q如果不存在则徏立此目录 4Q?/font> ?/span>1000目录下创?/span>DWORD|名字?/span>1207Qgؓ(f)0 5Q?/font> 重启vs2005/2008
q样可以保证万无一׃(jin)Q?/div>
]]>
]]>
class BinaryHeap
{
private:
int Size;
T * Tarr;
public:
BinaryHeap();
void insert(T x);
T deleteMin();
~BinaryHeap();
};
template<class T,int MAX>
BinaryHeap<T,MAX>::BinaryHeap()
{
Tarr=new T[MAX+1];
if(Tarr==NULL) {cout<<"创徏数组p|"<<endl;return ;}
Size=0;
}
template<class T,int MAX>
void BinaryHeap<T,MAX>::insert(T x)
{
++Size;
if(Size==MAX) return;
int i;
for(i=Size;Tarr[i/2]>x;i/=2)
Tarr[i]=Tarr[i/2];
Tarr[i]=x;
}
template<class T,int MAX>
T BinaryHeap<T,MAX>::deleteMin()
{
if(Size==0) return 0;
T minem=Tarr[1];
T lastem=Tarr[Size--];
int i,child;
for(i=1;i*2<=Size;i=child)
{
child=i*2;
if(child!=Size-1&&Tarr[child+1]<Tarr[child])
++child;
if(lastem>Tarr[child])
Tarr[i]=Tarr[child];
else
break;
}
Tarr[i]=lastem;
return minem;
}
template<class T,int MAX>
BinaryHeap<T,MAX>::~BinaryHeap()
{
delete[] Tarr;
}
]]>
const int MAX=1000003;
template <class T>
class hash
{
private:
int pos;
int next[MAX];
int head[MAX];
T key[MAX];
public:
hash();
bool search(T x);
void push(T x);
};
template <class T>
hash<T>::hash()
{
pos=0;
memset(next,-1,sizeof(next));
memset(head,-1,sizeof(head));
//memset(key,-1,sizeof(key));
}
template <class T>
inline bool hash<T>::search(const T x)
{
int temp=x%MAX;
int t=head[temp];
while(t!=-1)
{
if (key[t]==x)
{
return 1;
}
t=next[t];
}
return 0;
}
template <class T>
inline void hash<T>::push(const T x)
{
int temp=x%MAX;
if (head[temp]!=-1)
{
next[pos]=head[temp];
}
head[temp]=pos;
key[pos]=x;
pos++;
}
]]>
写一个备份文件的脚本Q利用crontab定时执行?/p>
步骤如下Q?/p>
1Q设|备份目的目?/p>
2Q进入目的目?/p>
3Q获取时_(d)讄备䆾文g?/p>
4Q备份文?/p>
#1Q获取root/bak字符?/p>
#2Q?z选项判断是否为空
#3Q如果ؓ(f)I就创徏目录
#4Q进入该目录
#5Q获取当前时?/p>
#6Q设|备份文件名
#7Q将/etc目录下所有文件打包备?/p>
-z 用gizp压羃和解压羃文gQ若加上此选项创徏的压~包Q解压的时候也许要加上此选项
-c 创徏新的?/p>
-v 详细报告tar处理文g的信?/p>
-f 使用压羃文g或设备,该选项通常事必选的
定时执行脚本需要修改etc中的 crontab文g
* * * * * #表示每分?/p>
1 * * * * #表示每小时的W一分钟
2 12 * * * #表示每天?2Q?2
0-59/2 * * * * #每两分钟执行一ơQ?/p>