• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Where there is a dream ,there is hope

              C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              64 Posts :: 0 Stories :: 8 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(1)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            2011年11月6日 #

            首先聲明:忙,保證持續(xù)更新不保證結(jié)束時(shí)間,估計(jì)一周左右寫完,忙的話兩周。涉及到對(duì)創(chuàng)新工場、李開復(fù)人品、移動(dòng)互聯(lián)網(wǎng)等的看法代表我魏小康的個(gè)人看法,版權(quán)所有,轉(zhuǎn)載請(qǐng)務(wù)必注明。 
              
            大綱: 
            一、緣由、概述 
            二、創(chuàng)新工場的模式 
            三、職業(yè)發(fā)展道路的影響因素 
            四、職業(yè)選擇的幾個(gè)小問題 
            五、李開復(fù)的移動(dòng)互聯(lián)網(wǎng)和我眼中的移動(dòng)互聯(lián)網(wǎng) 
            六、再見和祝福 
              
            一、緣由、概述 
            1、緣由     
                 前兩周,有個(gè)師弟咨詢我個(gè)offer選擇——360產(chǎn)品經(jīng)理offer和創(chuàng)新工場某團(tuán)隊(duì)產(chǎn)品經(jīng)理。他說面試的時(shí)候,創(chuàng)新工場某面試官說在360做產(chǎn)品經(jīng)理不如在創(chuàng)新工場,360那邊產(chǎn)品團(tuán)隊(duì)XX不專業(yè),創(chuàng)新工場這邊產(chǎn)品團(tuán)隊(duì)XX牛B,勸說這人推掉360的offer接創(chuàng)新工場的offer。 
                 我當(dāng)時(shí)聽了那叫一個(gè)汗阿——能說出這樣話的人要么特別無知要么特別無恥。別的不說,就沖360可以監(jiān)控?cái)?shù)億網(wǎng)民上網(wǎng)習(xí)慣這點(diǎn)也該去360阿。何況,360產(chǎn)品經(jīng)理做出的產(chǎn)品有多少人用,你創(chuàng)新工場有多少人用。 
                最近估計(jì)是創(chuàng)新工場開始發(fā)offer了,不斷有人咨詢我這家公司,加上有些人咨詢我另外的offer比較問題。我本來是懶得寫長文的,只是最近看到李開復(fù)的一些過于XX的言論,再加上前幾天聽說了創(chuàng)新工場忽悠師弟師妹們簽約而說一些極為荒唐的理由,實(shí)在看不下了。 
                 so,寫一篇吧。     
              
            2、概述 
                 我并不是反對(duì)大家去創(chuàng)新工場, 如果你生下來就是做老板的(不是自認(rèn)為,而是你在學(xué)校的時(shí)候已經(jīng)有不少成功的創(chuàng)業(yè)經(jīng)驗(yàn)),而且你很聰明,很勤奮,人格沒啥短板,你可以考慮去,也只有這種人在創(chuàng)新工場才有前途,創(chuàng)新工場也只適合這種人。 
                 如果你以后的職業(yè)目標(biāo)是個(gè)行業(yè)專家或者是企業(yè)中高級(jí)管理層,那么你還是老老實(shí)實(shí)找個(gè)發(fā)展較為迅速的企業(yè)賣命干著。現(xiàn)在互聯(lián)網(wǎng)發(fā)展這么快,你去搜狗、360的核心部門,乃至美團(tuán)、去哪兒、開心等未來成功的概率都比去創(chuàng)新工場大。 
                 如果你的職業(yè)目標(biāo)是賺的差不多就行了,比其他人強(qiáng)一些,別太累,收入中上,那你找個(gè)百度、騰訊等成熟部門安安心心做個(gè)螺絲釘就可以了。 
              
                 對(duì)于普通人,什么時(shí)候時(shí)候適合去創(chuàng)新工場?找實(shí)習(xí)的時(shí)候,正式工作還是算了。 
                 我寫這片文章,只是想告訴大家,創(chuàng)新工場模式的運(yùn)轉(zhuǎn)思路,學(xué)生加入會(huì)有哪些風(fēng)險(xiǎn),你該如何選擇一個(gè)offer,移動(dòng)互聯(lián)網(wǎng)的泡沫。如果最后有精力就寫寫offer的比較吧。 
              
            二、創(chuàng)新工場的模式,學(xué)生加入的問題、學(xué)生創(chuàng)業(yè) 
            (在看之前,請(qǐng)先去了解一下“天使投資人”、“A輪”、“B輪”的大概意思,了解一下天使投資的成功率,了解一下紅杉樹等大型VC A、B輪的成功率) 
              
            1、創(chuàng)新工場的模式 
            a.VC的模式 
                 紅杉樹、經(jīng)緯投資等知名VC,他們一般是在企業(yè)有一定的規(guī)模,有較為清晰的盈利模式的時(shí)候才進(jìn)入,用較高的錢換取較低的股份和較高的成功率。 
                而天使投資,是在產(chǎn)品剛有個(gè)雛形,甚至只有個(gè)idea的時(shí)候進(jìn)入,用較少的錢換取較高的股份,承擔(dān)非常高的失敗率,單個(gè)項(xiàng)目一旦成功會(huì)有很高的收益率。 
              
            b.天使投資者創(chuàng)新工場的優(yōu)勢 
            天使投資的收益=項(xiàng)目數(shù)×成功率×投資回報(bào)率—項(xiàng)目數(shù)×平均項(xiàng)目成本 
            大家可以看到,這個(gè)模式的關(guān)鍵點(diǎn)在于: 
            (1)、項(xiàng)目多: 
                天使投資人,投的項(xiàng)目成功概率都很低,李開復(fù)也絕對(duì)不會(huì)例外。項(xiàng)目差不多靠譜就上,創(chuàng)新工場拼的就是量; 
            (2)、平均成本低: 
                IT團(tuán)隊(duì)初期的成本主要是人員、硬件投入、場地以及行政、法律開支等。 
                人員:都創(chuàng)業(yè)了,你要什么高工資?給你期權(quán)忽悠一下就行。 
                硬件、帶寬、場地、行政:這塊創(chuàng)新工場集約化了,人越多,項(xiàng)目越多,這塊成本越低。 
              
                看到上述模式了?說白了,最關(guān)鍵的就是要量大,至于成功率差不多就行。米聊、UC做那么大,都快被qq放倒了,目前創(chuàng)新工場投的這些項(xiàng)目有什么好顧慮的? 
              
                而李開復(fù)在做量這方面擁有著獨(dú)特的杠桿,他的主要受眾就是——學(xué)生和入世不深的資源匱乏者。這批人是最需要天使投資人的,這批人也是最容易被忽悠加入創(chuàng)業(yè)團(tuán)隊(duì)的。因此,他能夠幫助:投資人解決項(xiàng)目數(shù)量問題,幫助創(chuàng)業(yè)者的老板解決掉招聘問題(招聘問題一般是初創(chuàng)團(tuán)隊(duì)面臨的最大問題)。 
                因此,目前就天使投資的規(guī)模來說,創(chuàng)新工場是最大的。這也是為什么李開復(fù)的微博一說話,VC們都出來捧場,因?yàn)樗掷镯?xiàng)目多,VC都等著A、B輪的時(shí)候跟進(jìn)的。你還會(huì)發(fā)現(xiàn),互聯(lián)網(wǎng)大佬們相互之間的互動(dòng)不算少,但是鮮有轉(zhuǎn)發(fā)、評(píng)論李開復(fù)的微博,因?yàn)榇蠹揖退愣贾浪牌ǎ铋_復(fù)也沒仇,李開復(fù)PR做的又那么好,惹他干嗎?但是如果轉(zhuǎn)了傷自己的RP也不好。 
               
              
                 so,創(chuàng)新工場這事,本來也沒啥特別的,就是一個(gè)大型天使投資機(jī)構(gòu)投資了一大批初創(chuàng)團(tuán)隊(duì)。這些創(chuàng)業(yè)團(tuán)隊(duì)再閃亮,也是一堆初創(chuàng)團(tuán)隊(duì),跟其它創(chuàng)業(yè)團(tuán)隊(duì)一樣,有很多問題,也會(huì)有一些機(jī)會(huì),也存在很大的風(fēng)險(xiǎn)。但是由于某人的影響力,加上最近移動(dòng)互聯(lián)網(wǎng)的泡沫,收益被無限地放大了,風(fēng)險(xiǎn)看起來被縮小了。 
                 李開復(fù)在招聘的時(shí)候到處去忽悠,其實(shí)也沒啥,哪個(gè)公司招人的時(shí)候不到處忽悠呢?否則開什么宣講會(huì)?只不過開復(fù)同志到處對(duì)沒有辨別能力的學(xué)生去忽悠加入創(chuàng)新工場機(jī)會(huì)大大、回報(bào)高高、風(fēng)險(xiǎn)低低,這實(shí)在有點(diǎn)惡心人。 
                對(duì)于投資人、創(chuàng)業(yè)的老板來說,創(chuàng)新工場不錯(cuò),投資回報(bào)率高,但是對(duì)于員工來說,風(fēng)險(xiǎn)高收益低,遠(yuǎn)遜于加入其它公司。一將功成萬骨枯,2、3年過后,李開復(fù)成功的時(shí)候,誰會(huì)記得這些無辜的應(yīng)屆生呢? 
              
            下面我說一下加入這樣團(tuán)隊(duì)的風(fēng)險(xiǎn)。 
            ——————————————————————————————————————— 
            未完,明后天爭取 繼續(xù)二更。 
              
            20111103日二更———————————————————————————————————————————————— 
              
            三、職業(yè)發(fā)展道路的影響因素 
              
            1、職業(yè)規(guī)劃基本理論 
                先講兩個(gè)基本的理論: 
                我自創(chuàng)了一套評(píng)價(jià)人的體系,大概的意思就是人可以分為四個(gè)維度去觀察,人格、能力、知識(shí)、其它方面(如人際關(guān)系的等)。 
                我也自己在摸索一些職業(yè)規(guī)劃的理論,還沒完全定型,初步地講,做職業(yè)規(guī)劃是從:行業(yè)、職業(yè)、公司、地點(diǎn)等維度去分析。 
                所謂的職業(yè)規(guī)劃,就是選擇合適的行業(yè)、職業(yè)、公司等,幫助自己以最大的概率快速地獲得職業(yè)的高點(diǎn)。至于如何才能取得職業(yè)規(guī)劃效益的最大化,話題太大,就不講了,只講講“新人入職場”和“為什么不是創(chuàng)新工場”。 
               
            2、職業(yè)發(fā)展的兩條道路 
                李開復(fù)光說加入創(chuàng)新工場比加入百度、騰訊成功概率高,但是怎么個(gè)高法、怎么個(gè)鍛煉法,沒說。我也一直蠻好奇的,如何能讓一個(gè)人在創(chuàng)新工場成功概率比在百度、騰訊高?我覺得李開復(fù)如果能做到,作為百度、騰訊的股東,我會(huì)申請(qǐng)發(fā)起股東會(huì)投票,呼吁李彥宏、化騰下課讓賢。 
                在沒看到結(jié)果之前,我們還是先理論分析一下,單從職業(yè)發(fā)展角度,如何才能更為成功。做獵頭這么多年了,我也大概琢磨出來了——人的最終發(fā)展結(jié)果無非兩種,業(yè)務(wù)專家 or 管理層. 
                 這個(gè)跟你是否要?jiǎng)?chuàng)業(yè)還是打工無關(guān),你是騰訊的創(chuàng)始人、百度的部門經(jīng)理、創(chuàng)新工場的項(xiàng)目負(fù)責(zé)人,你承擔(dān)的也還是這兩類角色。因此,你找工作,要找的就是能幫助你在未來幾年內(nèi)成為這類角色的公司、職位,只要一個(gè)公司能幫助你成為業(yè)內(nèi)的專家、管理層,咱就可以坐下來談offer。管你這家公司是百度、騰訊還是國務(wù)院。 
              
                 管理層需要的東西我們就不談了,談這個(gè)對(duì)于應(yīng)屆生太扯淡了。如果有人能教會(huì)一個(gè)應(yīng)屆生如何快速成為高級(jí)管理層,我覺得只在一種場合里面有——做傳銷的,熱衷給你講如何在1、2年內(nèi)快速成功,快速當(dāng)上家。 
                 我認(rèn)為想做管理層,沒啥捷徑,先成為你們小組的小組長再說。見過提拔業(yè)績好的當(dāng)組長的,沒見過提拔業(yè)績差的當(dāng)組長的公司,so,如何當(dāng)管理層這事,你可以工作1、2年升了組長后去職場版再討論。 
                so,新人的你,第一步是得研究如何成為小組內(nèi)的專家。 
              
            3、如何能快速當(dāng)上專家 
                結(jié)合如何成為一個(gè)行業(yè)知名專家或者公司內(nèi)的專家這個(gè)目標(biāo),我們來分析一下職業(yè)規(guī)劃跟求職者自身情況的匹配。行業(yè)就不分析了,這話題太大了,最多過兩天寫寫移動(dòng)互聯(lián)網(wǎng)的情況。 
              
            (1)職業(yè)和人格,職業(yè)轉(zhuǎn)換的高昂成本 
                想成為專家,首先應(yīng)該看自己的人格適合什么職業(yè),做自己不適合做的事情,肯定成不了專家。這個(gè)職業(yè)不應(yīng)該是入職后去各種嘗試,工作后轉(zhuǎn)行的成本太高。要知道,你再跳槽的時(shí)候,招聘方只對(duì)專家和管理層的人感興趣,對(duì)于想換職業(yè)方向的人從來不會(huì)感興趣,誰有興趣招個(gè)目前做運(yùn)營的過來寫代碼?or招個(gè)寫C++的過來做產(chǎn)品? 
                轉(zhuǎn)職業(yè)的成本非常高昂,因此嘗試各種職業(yè)、各個(gè)方向應(yīng)該是在你做實(shí)習(xí)的時(shí)候,這也是我為什么說創(chuàng)新工場非常適合去實(shí)習(xí)的原因,太合適了,團(tuán)隊(duì)小,不談做的專業(yè)否,但是每個(gè)人都得干好幾塊事情,各個(gè)職位都有機(jī)會(huì)接觸到。 
              
            (2)當(dāng)專家需要啥?   
                當(dāng)專家需要啥?主要是兩塊:職業(yè)相關(guān)的能力,如溝通、邏輯、學(xué)習(xí)等;業(yè)務(wù)相關(guān)知識(shí),如XX開發(fā)語言、某工具掌握等,那么如何能快速提升能力、構(gòu)建知識(shí)體系? 
                國內(nèi)沒啥成熟的理論,國際的我也沒看到,我自己個(gè)人認(rèn)為以下一些因素是必要的:良好的職業(yè)習(xí)慣、科學(xué)的學(xué)習(xí)工作方法思路、有大牛帶你、少走彎路。理論粗糙,還請(qǐng)大家補(bǔ)充。 
                 
            (3)職業(yè)習(xí)慣    
                職業(yè)習(xí)慣:大公司或者稍微正規(guī)的公司,都會(huì)有各項(xiàng)流程文檔、規(guī)章制度,或者有人帶你教你。這非常有助于養(yǎng)成良好的職業(yè)習(xí)慣:常規(guī)事情處理流程、團(tuán)隊(duì)協(xié)作流程、郵件、文檔寫作規(guī)范、程序開發(fā)規(guī)范、開會(huì)制度,甚至如outlook、office的使用。這些職業(yè)習(xí)慣的養(yǎng)成,可以很好地提高你的做事效率,提高你跟公司的協(xié)同效率,提高大家做事情的成功率。 
                 我就舉個(gè)小例子,我們公司是小公司,但是我們會(huì)對(duì)員工windows、office的幾十個(gè)快捷鍵做考試,考試不過的,要求全鍵盤不用鼠標(biāo)干活一天。這些快捷鍵的掌握可以讓一個(gè)經(jīng)常處理文檔的員工每天節(jié)約20分鐘,一年就是120個(gè)小時(shí),相當(dāng)于15個(gè)工作日。 
                對(duì)于普通人而言,第一件事情就是該學(xué)會(huì),如何讓自己做事更合行業(yè)、公司的規(guī)矩、流程,能在這些范圍內(nèi)盡可能地提高業(yè)績。如果你有一天完全掌握且能改進(jìn)、顛覆公司規(guī)則,你就能當(dāng)你們公司的專家或者管理層,如果你有一天能改進(jìn)、顛覆行業(yè)的規(guī)則、流程,那你就能創(chuàng)業(yè)、開山立派了。 
                別看大公司的流程瑣碎,流程的存在實(shí)際是為了提高效率,這事工作三年以上的人都會(huì)認(rèn)同。否則騰訊、百度就不用這兩年花大力氣從華為、IBM等挖人過來改進(jìn)管理了,不強(qiáng)調(diào)流程、制度的公司大多都是一些小作坊式的公司,沒前途更沒錢途。 
            (4)科學(xué)的學(xué)習(xí)工作方法思路 
                這個(gè)就不多說了,每個(gè)行業(yè)、職業(yè)都不一樣,但是相同的是都肯定有方法。做分布式開發(fā)應(yīng)該先學(xué)什么,先做什么,有什么常規(guī)的模型、工具,做產(chǎn)品規(guī)劃有哪些常規(guī)產(chǎn)品規(guī)劃方法、工具。做獵頭分哪幾個(gè)階段,每個(gè)階段應(yīng)該掌握什么能力、知識(shí),如何做才能掌握這些能力、知識(shí)等等。   
            (5)大牛帶、經(jīng)驗(yàn)的積累: 
                 記得職場版有個(gè)新浪的小伙子寫過一個(gè)帖子,講他漲薪的經(jīng)歷,寫的蠻實(shí)在的。其中有一條我記得大概的意思就是,每天晚上加班看前人的文檔、操作記錄,看公司的前輩們?nèi)绾翁幚韱栴}、解決問題的。這些行業(yè)知識(shí)、經(jīng)驗(yàn)有些公司是形成文檔的,有些公司是靠你老大教給你的,在這方面,如果是大牛或者公司有成熟的知識(shí)、經(jīng)驗(yàn)分享制度,那會(huì)讓你少走很多彎路。 
                這個(gè)非常重要,別人可能幾個(gè)月、一兩年處理故障、遭遇的問題、瓶頸濃縮在你職業(yè)道路不同時(shí)期、恰到好處的幾次培訓(xùn)中,會(huì)讓你少摸索很多年。平時(shí)樂于給你分享知識(shí)、經(jīng)驗(yàn),把他多年的知識(shí)分享給你,而不是沒人分享——前提是知識(shí)是正確的。 
            (6)少走彎路 
                 這個(gè)彎路主要是指由于其它人,公司帶來的影響,例如產(chǎn)品人員水平一般,導(dǎo)致需求經(jīng)常變化,開發(fā)人員疲于奔命。公司渠道資源有問題,大家辛苦做出的產(chǎn)品上線訪問量低,無從得到 消費(fèi)者的真實(shí)反饋,無法改進(jìn)產(chǎn)品。或者像米聊這樣,在明知道會(huì)有微信這樣的對(duì)手會(huì)出現(xiàn)的情況下,還投入這么大的財(cái)力、物力去做,跟當(dāng)年金山office號(hào)稱要打垮MS有啥區(qū)別。 
                 一個(gè)產(chǎn)品從做出來到有用戶,到有大量用戶,到成為行業(yè)第一,到發(fā)展遭遇瓶頸沒法再提高,你從中收獲到的經(jīng)驗(yàn)是截然不同的,總是在低水平重復(fù)是沒有意義的。像我們做獵頭,從R到AC、C、SC、MC每步都是不一樣的,一年協(xié)助別人做幾十萬的業(yè)績到自己帶團(tuán)隊(duì)做幾百萬是不一樣的。 
              
              
            ——————————————————————————————————————————————— 
            抱歉,看到微博催更的童鞋,加班完回來抓緊寫了會(huì)。 
            今天就寫到這了,人手緊張,天天加班,明天還得早起,先洗洗睡了,明后天有空再寫下一節(jié)——為什么不是創(chuàng)新工場、李開復(fù)的人品、移動(dòng)互聯(lián)網(wǎng),爭取一氣或兩氣呵成。  
              
              
              
            20111104三更—————————————————————————————————————————————————————— 
              
            四、找工作的常見幾個(gè)誤區(qū)——主要是指在互聯(lián)網(wǎng)行業(yè) 
                 由于最近收到了各種渠道的善意的、不善意、赤裸的、隱晦的關(guān)愛、提醒、暗示、威脅,那家公司和某人的情況就不寫了,下面兩章僅就一些求職的小問題和移動(dòng)互聯(lián)網(wǎng)做個(gè)探討。 
                 至于那家公司情況到底如何,北郵也有很多童鞋在那實(shí)習(xí)過,找人問問就知道了。問問各個(gè)團(tuán)隊(duì)的重組是否頻繁,管理如何,流程是否有,如果有流程是否順暢,培訓(xùn)是否滿足日常工作的需要,老大是否很有經(jīng)驗(yàn)?zāi)茏屝〉苌僮邚澛罚_發(fā)運(yùn)營是否經(jīng)常做無用功,對(duì)比對(duì)手自己的產(chǎn)品推廣渠道是否給力,問問社招的人都是啥情況(這個(gè)可以對(duì)比一下同為創(chuàng)業(yè)公司的美團(tuán)的開發(fā)團(tuán)隊(duì),兩者比較,你就可以得出來有工作經(jīng)驗(yàn)的人如何看待創(chuàng)新工場和美團(tuán))……把這些按照我上文寫的那些標(biāo)準(zhǔn),跟其它offer做比較分析就可以了。 
              
                 在這里,還講個(gè)簡單的方法,今年HR的校招招聘壓力很大,你如果拿了多家公司的offer,不知道如何權(quán)衡,可以直接去問HR。讓HR和業(yè)務(wù)部門給你建議,分析各家offer的優(yōu)劣,HR和業(yè)務(wù)部門會(huì)很盡心盡責(zé)地給你講的,多聽幾家的HR分析,你就知道該如何選擇了。在這其中你也能看出各個(gè)HR和業(yè)務(wù)老板的人品到底如何。 
                 說到這,我是真不知道某些新注冊(cè),發(fā)文為0,or故意跳出來講“哪家公司招聘的時(shí)候不忽悠,李開復(fù)忽悠怎么了?”的人是個(gè)啥意思?意思是別的HR都忽悠了,某人忽悠大點(diǎn),影響惡劣點(diǎn)就不算事了? 
              
                在此,討論幾個(gè)小問題進(jìn)行討論。 
            1、去大公司就是一定當(dāng)螺絲釘 
                李開復(fù)宣講的時(shí)候說“我去大公司工作過,他們說,恭喜你,加入了全世界最牛的某某項(xiàng)目組,今后你的工作就是寫一個(gè)按鈕。”,這句話,按照心理學(xué)講,叫心理暗示——看著是說自己的經(jīng)歷,但卻給你暗示“你去大公司就是做螺絲釘,就是寫按鈕”。 
                 我想說,某人是揣著明白裝糊涂,有點(diǎn)睜眼說瞎話的意思。你去IBM、MS、通信業(yè)可能是這個(gè)樣子,行業(yè)很穩(wěn)定,必然了。但是在互聯(lián)網(wǎng)行業(yè),明明是完全不同的。 
                 李開復(fù)又不是沒在google呆過,他在google的時(shí)候不是很提倡給員工時(shí)間讓員工自己來嘗試一些東西嗎?在google那么大的公司里面,不是很多研發(fā)都自己試過規(guī)劃產(chǎn)品、運(yùn)營產(chǎn)品嗎?他這么快就忘了? 
                 中國的互聯(lián)網(wǎng)發(fā)展才這么幾年,大部分企業(yè)有沒什么成熟的流程制度來讓員工變成螺絲釘?也就baidu、騰訊這兩年不愁生死了,在嘗試做這方面的流程制度。 
                大部分互聯(lián)網(wǎng)公司都在擔(dān)心明年、現(xiàn)在的生死問題,沒有精力搞什么螺絲釘制度。研發(fā)為什么不能參與產(chǎn)品設(shè)計(jì)?研發(fā)為什么不能幫助運(yùn)營抓取數(shù)據(jù)來分析?產(chǎn)品為什么不能參與運(yùn)營來規(guī)劃活動(dòng)?競爭對(duì)手都把產(chǎn)品上線了,用戶數(shù)都好幾十萬了,那還有那么多規(guī)矩?你們還不抓緊以效率優(yōu)先!干嘛呢!你們幾個(gè)研發(fā)和產(chǎn)品抓緊碰一下,趕緊做出來先上線,看著運(yùn)營數(shù)據(jù)直接改!再做不出來把你們都裁了。 
                所有的互聯(lián)網(wǎng)公司,包括百度、騰訊在內(nèi)(除了一些非常成型的部門,例如新浪的新聞網(wǎng)站部門等,以及一些非常重量級(jí),必須分的很細(xì)的工作,如網(wǎng)頁搜索),不管你是研發(fā)還是其它,只要你愿意,你可以很輕松地接觸到別人的工作,甚至可以參與部分(當(dāng)然,大量地參與就算了,該干點(diǎn)啥干點(diǎn),別把副業(yè)當(dāng)主業(yè))。 
                各個(gè)互聯(lián)網(wǎng)企業(yè)的實(shí)際情況,請(qǐng)自己去問問論壇的各個(gè)師兄師姐,自己師兄師姐的說法,比李開復(fù)靠譜的多。我所知道的是:我們微軟、寶潔、華為等公司的候X選X人(你妹的,那三個(gè)字居然是敏感詞,害我嘗試了無數(shù)遍,用了二分查找算法才找到敏感詞)去了baidu、騰訊,第一反應(yīng)就是——靠,這些互聯(lián)網(wǎng)公司管理怎么這么混亂、職責(zé)變來變?nèi)ィa(chǎn)品動(dòng)不動(dòng)就調(diào)整?我怎么還要承擔(dān)別的部門的工作職責(zé)?百度、騰訊尚且如此,就更不用說其它公司了。
              
              
            2、輪崗、兼作 
               術(shù)業(yè)有專攻,你相信一個(gè)人又做產(chǎn)品又干研發(fā),比專做產(chǎn)品能做的更好?你作為一個(gè)新人,能把一樣?xùn)|西做好就行了。很多東西你了解一下不就行了嗎?為什么要做兼作?專做一件事情,對(duì)你的能力、知識(shí)等提升更快。 
              
                如果有人對(duì)你說經(jīng)常換部門對(duì)于當(dāng)管理層有幫助的,除非那人是你爸,他準(zhǔn)備讓你輪崗之后當(dāng)CEO,否則趕緊踹他一腳給他一巴掌讓他閉嘴。在目前的中國,已經(jīng)有成熟的輪崗、提升計(jì)劃,且有成功先例的大公司一只手就數(shù)過來了。這幾年,很多公司的管理培訓(xùn)生計(jì)劃最后都不了了之,招進(jìn)去的人打落牙齒和血吞,更多的是變成了銷售培訓(xùn)生的代名詞。更不用說在沒有輪崗、培養(yǎng)規(guī)劃的公司里面了這些人會(huì)落個(gè)什么結(jié)果。 
                
                一個(gè)公司如果說,我們打算讓你多干幾塊工作,專注提高一下,我只能說——他在忽悠你。我再舉個(gè)例子,在我們獵頭業(yè),有些獵頭公司哪怕一些大的獵頭公司,員工是進(jìn)來之后分個(gè)大行業(yè),然后不分細(xì)分行業(yè),不分職業(yè)角色都做。你可以想想,一個(gè)人又做互聯(lián)網(wǎng)研發(fā)類的職位,又做通信類銷售的職位,還做軟件類測試的職位,他最后挖人的時(shí)候能比得過專做移動(dòng)互聯(lián)網(wǎng)研發(fā),專做通信業(yè)銷售的獵頭嗎? 
              
            3、可以快速致富 
                收益=成本×投資回報(bào)率×(1-失敗率) 
                你在年輕的時(shí)候,成本是10~20萬(你的薪水、期權(quán)),回報(bào)率是300%(給底層員工這個(gè)回報(bào)率了不起了),失敗率是99.9%(眼光不行,不具備判斷力;能力不夠,沒法控制局面降低風(fēng)險(xiǎn))。 
                你在3、40歲的時(shí)候,成本是4、50萬,回報(bào)率是3000%甚至百倍(給部門經(jīng)理的,給創(chuàng)業(yè)骨干的肯定不一樣),失敗率是90%(創(chuàng)業(yè)風(fēng)險(xiǎn)總是有的)。 
                你自己算算帳吧。 
            4、暴富機(jī)會(huì)一去不復(fù)返 
                引用李開復(fù)老師的一句話來回答——“中國平均九年出現(xiàn)一次大發(fā)財(cái)成功機(jī)會(huì)”,所以你不用急著去趕李開復(fù)老師宣傳的這次移動(dòng)互聯(lián)網(wǎng)熱潮。9年后還有呢。 
              
                引用我寫《通信行業(yè)求職寶典》寫的一段話:“10年前,沒有人會(huì)想到SP公司會(huì)這么掙錢,新浪、搜狐等公司能靠著SP業(yè)務(wù)撐過了互聯(lián)網(wǎng)最為寒冷的一段時(shí)間。8年前,沒有沒有人會(huì)想到RIM會(huì)憑借黑莓達(dá)到一年60億美元的年收入,凈利潤可以達(dá)到13億美元;6年前沒有人會(huì)想到彩鈴也會(huì)掙錢,一首“瘋狂青蛙”居然能帶來4000多萬英鎊的收入,4年前沒有人會(huì)意識(shí)到彩信報(bào)這種幾個(gè)人就可以做的產(chǎn)品會(huì)有數(shù)百萬數(shù)千萬的訂閱者,2年前沒人想到RIM很快就沒落過時(shí)了,1年前沒人想到移動(dòng)互聯(lián)網(wǎng)的泡沫會(huì)如此之大……” 
              
            5、期權(quán) 
                我只想說,我認(rèn)識(shí)的中高層候X選X人,談offer大家一般最關(guān)注的是薪水,鮮有最關(guān)注股票、期權(quán)的,越高層越如此,給股票、期權(quán)再多也不如給錢實(shí)在。公司給你股票期權(quán)是為了讓你暴富的還是為了讓你承擔(dān)公司發(fā)展風(fēng)險(xiǎn)的? 
                公司如果眼瞅著明年就一定能上市,或者公司股票明年一定比現(xiàn)在漲100%,公司為什么要給你這個(gè)撈錢的機(jī)會(huì)?股東方自己錢太多了? 
                收益越高,風(fēng)險(xiǎn)越高。如果有公司的期權(quán)能讓你比同齡人多30%的收益,那意味著這事還有點(diǎn)希望,要是能多100%,那意味著這事不靠譜, 
                要是能多1000%,那基本肯定這事沒啥希望了。 
              
            ——————————————————————————————————————————————————— 
            中場休息,吃夜宵,晚上再更一次最后一段,寫寫移動(dòng)互聯(lián)網(wǎng)。之前說的最后一部分“offer選擇”就不寫,沒時(shí)間,明天還要干活。 
              
            四更———————————————————————————————— 
              
              
            五、李開復(fù)對(duì)于移動(dòng)互聯(lián)網(wǎng)的看法和我對(duì)于移動(dòng)互聯(lián)網(wǎng)的看法 
                 簡單分析一下,細(xì)的東西大家可以自己分析。我給個(gè)分析的方法——多看看各個(gè)互聯(lián)網(wǎng)大佬的動(dòng)作和演講,多去問問師兄師姐各個(gè)公司實(shí)際的人力、財(cái)力投入。跟著業(yè)內(nèi)的大佬,而不是記者、愛炒作的人走,你一般成功概率會(huì)更高一些。 
              
            1、移動(dòng)互聯(lián)網(wǎng)的市場前景: 
                 “如果傳統(tǒng)互聯(lián)網(wǎng)的三大巨頭,百度騰訊阿里加在一起,值一千五百億美金的話,那么,移動(dòng)互聯(lián)網(wǎng)三個(gè)巨頭,將是一千五百億美金的十倍,一萬五千億美金。”  
                 對(duì)于這段話,互聯(lián)網(wǎng)大佬們大多選擇了無視,VC們大多選擇了支持這段話。有個(gè)互聯(lián)網(wǎng)老大隱諱地調(diào)侃了一下,當(dāng)然,人家說的很客氣,不像我說的那么直接,他說的是“美國股市市值最高的三家公司,埃克森美孚/蘋果/微軟加起來市值9千多億美元,中國無線互聯(lián)網(wǎng)三巨頭10年后市值加起來要達(dá)到1.5萬億......中國人民,站起來了......”。 
              
                 他列舉的是美國前三,而全世界市值前三的公司加起來都沒有一萬五千億……我估計(jì)李開復(fù)1.5萬億的計(jì)算基礎(chǔ)是全球貨幣高速貶值,而不是移動(dòng)互聯(lián)網(wǎng)高速發(fā)展。 
              
            2、機(jī)會(huì)大 
            “這個(gè)機(jī)會(huì),我可以保證,絕對(duì)比1999年的更大,也許大五倍,也許大十倍,或者五十倍,具體大多少我不好說,但是我肯定,絕對(duì)比當(dāng)年丁磊馬云的機(jī)會(huì)要大很多。” 
              
                 網(wǎng)易手里有著一百多億的現(xiàn)金,既然這個(gè)機(jī)會(huì)比丁磊當(dāng)年大多了,那丁磊為什么不投個(gè)幾億招幾百人過來開發(fā)? 
                 現(xiàn)在全國所有的移動(dòng)互聯(lián)網(wǎng)項(xiàng)目加起來還不夠網(wǎng)易一家收購的。網(wǎng)易直接都買了,然后就可以直接再造一個(gè)百倍于網(wǎng)易的公司,豈不是最快捷? 
                 做為曾經(jīng)的中國首富,第一代互聯(lián)網(wǎng)CEO,目前中國最賺錢的三家互聯(lián)網(wǎng)公司之一的老板,丁磊的互聯(lián)網(wǎng)從業(yè)、燒錢、賺錢經(jīng)驗(yàn)可比李開復(fù)豐富多了。
              
            3、發(fā)展 
            “你要來創(chuàng)新工場,從基層做起,從工程師做起。你在百度微軟中國銀行,可能十年二十年,你能成為一個(gè)中層或高層管理者,而在創(chuàng)業(yè)公司,快的兩三年,慢的七八年,完全有可能創(chuàng)業(yè)成功。” 
              
            唉,兩三年的中高層,讓我們羞愧地掩面而泣阿。  
              
            4、產(chǎn)品競爭激烈度 
                 大家去看看豌豆莢的產(chǎn)品,再去看看qq推出的應(yīng)用助手。豌豆莢是去年4月份推出來的,qq應(yīng)用助手是今年8月推出來的,兩者一個(gè)推出來了18個(gè)月,一個(gè)推出來了3個(gè)月,你去看看現(xiàn)在兩者功能的差距。qq運(yùn)用助手不知道現(xiàn)在裝機(jī)量超過豌豆莢沒有,就算沒超過,我估計(jì)也就是幾個(gè)月的事情。 
              
                 大家再隨便去qq旗下挑一些手機(jī)客戶端產(chǎn)品,看看適配的終端種類,再去業(yè)內(nèi)的其它移動(dòng)互聯(lián)網(wǎng)新秀們看看?不在一個(gè)量級(jí)。 
                 Android給了很多手機(jī)公司機(jī)會(huì),但是也給軟件開發(fā)者帶來了巨大的麻煩。就例如終端適配這個(gè)事情,不做,用戶體驗(yàn)差,做,公司根本養(yǎng)不起這樣一個(gè)團(tuán)隊(duì)。有些時(shí)候我甚至覺得在移動(dòng)互聯(lián)網(wǎng)上做東西還不如在騰訊等的開放平臺(tái)上做東西,起碼不用去考慮各個(gè)終端的種類、版本、屏幕等。 
              
            5、渠道 
            “推銷不需要耗費(fèi)巨大的渠道費(fèi)用,直接經(jīng)過搜索社交引擎推廣” 
            ucweb做了那么大了,今年在預(yù)裝渠道里面被騰訊卡的死死的——你手機(jī)公司要么裝我的qq和qq瀏覽器,要么你裝他的Ucweb但是不能裝QQ,錢我給的更多。 
            沒錢,哪來的流量,真靠社交推廣就能推廣起來,360哪能那么霸氣當(dāng)軟件渠道商? 
              
                 這兩天還看到個(gè)很有趣的事情,跟大家分享一下。前幾天蘇寧易購圖書上線搞活動(dòng),京東也搞活動(dòng),當(dāng)當(dāng)也搞活動(dòng)。蘇寧的系統(tǒng)最爛,0點(diǎn)就掛了,3、4點(diǎn)才好,活動(dòng)也最一般。 
                 但在某幾家新聞門戶看到的報(bào)道都是“蘇寧易購血戰(zhàn)XXX,投入巨資不惜虧本”,半點(diǎn)沒提過系統(tǒng)掛掉的事情,而京東當(dāng)當(dāng)?shù)男侣勈?#8220;京東當(dāng)當(dāng)圖書戰(zhàn)被指花錢買罵名:大部分缺貨”,邊上還掛著一個(gè)新聞“京東重磅促銷遇網(wǎng)絡(luò)癱瘓 10月被投訴389起”。 
              
                 呵呵,有時(shí)間大家可以多觀察一下新浪、騰訊、搜狐的新聞,基本都是對(duì)掐,你看到的新聞都是資本家們想讓你看到的,不管是新聞網(wǎng)站還是微博。 
              
            6、移動(dòng)互聯(lián)網(wǎng)薪水和其它行業(yè)的薪水 
                 移動(dòng)互聯(lián)網(wǎng)發(fā)展很快很大,薪水被抬的很高。 
                 例如我們很多客戶開的條件都是:有1、2年的相關(guān)經(jīng)驗(yàn),能獨(dú)立干活的,不用名校畢業(yè),不用算法好,做Android的就能到20來萬,做iPhone的能到25萬,更高的也有。遠(yuǎn)超過同期其它行業(yè)的人,我們前幾年就看到這個(gè)趨勢,前兩年起就儲(chǔ)備人才,這一年收益頗多。 
                 但是,我們自己的判斷是,現(xiàn)在的薪水泡沫在2、3年左右會(huì)慢慢破掉,這個(gè)行業(yè)的門檻很低,技術(shù)難度并不大,這幾年進(jìn)去的應(yīng)屆生2、3年成長起來后就不會(huì)這么夸張。 
              
                 而且,移動(dòng)互聯(lián)網(wǎng)客戶端開發(fā)未來成長空間較小,畢竟比起后臺(tái)、搜索等,技術(shù)難度在那擺著。在我們知道的所有互聯(lián)網(wǎng)公司里面,起薪都很高,但是超過30萬薪水的職位很少,35萬的罕見,40萬的工程師職位沒見過幾個(gè)。但是我們做的分布式后臺(tái)、搜索、數(shù)據(jù)挖掘等職位,3、40萬的很普遍,1、200萬的職位也有,大家可以自己思考一下為什么。 
                 因此我覺得,如果你熱愛開發(fā),技術(shù)大牛,可以選擇后臺(tái)、數(shù)據(jù)挖掘、搜索等難度較大的,如果不是特別熱愛開發(fā),不是技術(shù)大牛,那你在Android開發(fā)和常規(guī)的一些開發(fā)職位中可以選擇Android開發(fā)之類的,畢竟都是工作,未來泡沫滅了也不會(huì)差到哪去,起碼近幾年收入不錯(cuò)。 
              
            7、移動(dòng)互聯(lián)網(wǎng)的創(chuàng)業(yè)環(huán)境和前景。 
                 移動(dòng)互聯(lián)網(wǎng)的機(jī)會(huì)不少,也是未來必然的趨勢,但是跟小團(tuán)隊(duì)沒啥關(guān)系,包括現(xiàn)在在iPhone應(yīng)用市場上,小團(tuán)隊(duì)存活的概率很低,開發(fā)、UI、推廣等都是要錢的,人員成本也很貴。 
                 有不少移動(dòng)互聯(lián)網(wǎng)小公司找我們招人,我們的第一句話就是你給我預(yù)付費(fèi)我也不給你們做,太難了。大公司都搶不過來人,何談小公司,so,這也是李老師為什么這么著急的原因。畢竟創(chuàng)新工場這2、3年能活下來,不管最后成幾個(gè)項(xiàng)目,他就算成功了,要是在這輪泡沫結(jié)束前活不下來,他可能就成為了第二個(gè)方東興。 
              
                 現(xiàn)在的創(chuàng)業(yè)環(huán)境比以前要糟糕,當(dāng)年遍地都是機(jī)會(huì),全是空白的,現(xiàn)在創(chuàng)業(yè)你能做的就是依附一顆大樹創(chuàng)業(yè),在qq、百度、阿里系等公司框下的圈子里面創(chuàng)業(yè),當(dāng)年的淘寶都畏懼百度,現(xiàn)在的京東都畏懼etao,何談其它。 
              
              
            8、創(chuàng)業(yè)門檻 
             “今天的創(chuàng)業(yè)和以前不一樣了,你只要做一個(gè)最低的不被用戶罵的產(chǎn)品,先推向市場。不要太花力氣琢磨用戶喜歡黑色還是紅色,一半黑一半紅,哪個(gè)黏性大就用哪個(gè),不要考慮讓用戶注冊(cè)好還是不注冊(cè)好,一半注冊(cè)一半不注冊(cè),看用戶反應(yīng)。如果你做汽車,一半黑一半紅,行嗎?成本太大,做軟件互聯(lián)網(wǎng)最大的好處,就是無本生意,用戶也不用付錢,互聯(lián)網(wǎng)就是你的實(shí)驗(yàn)室。” 
              “采用云計(jì)算,不需要買服務(wù)器和帶寬;采用開源軟件,大大節(jié)省工程師成本;推銷不需要耗費(fèi)巨大的渠道費(fèi)用,直接經(jīng)過搜索社交引擎推廣,大大節(jié)約了營銷成本……150萬就夠了。雖然不算很低,但這是歷史新低。 
              
                 論據(jù)我就不評(píng)價(jià)了,如果論點(diǎn)是正確的,的確門檻低,那么我想說——對(duì)創(chuàng)業(yè)者而言,在初期想撈一把就走,門檻低是個(gè)好事,如果在中后期,那簡直是個(gè)災(zāi)難,門檻越低競爭越激烈。只能比燒錢速度和兜里的銀子了。 
              
            9、移動(dòng)互聯(lián)網(wǎng)前景 
                 這話題太大了,我懶得寫,只想說,前景很開闊,但是走勢很難定,鹿死誰手未知,且未來移動(dòng)互聯(lián)網(wǎng)開發(fā)的難度、門檻、平臺(tái)到底是什么樣?不知道。當(dāng)有一天折疊屏幕、投影、電池技術(shù)都解決的時(shí)候,移動(dòng)互聯(lián)網(wǎng)和互聯(lián)網(wǎng)的界限真會(huì)那么清晰嗎?(貌似現(xiàn)在已經(jīng)很模糊了)。 
                 而且,輕客戶端,web化已經(jīng)成為了一個(gè)必然的趨勢,無線傳輸技術(shù)、材料學(xué)的發(fā)展給這個(gè)行業(yè)帶來了很多不確定性。 
               
              
            六、再見和祝福 
                 以后就慢慢不寫東西了,老了,從真情流露job版到北郵人論壇job版,該寫的東西都重復(fù)一萬遍了,沒有啥寫東西的欲望,也沒啥新東西好寫的,每年看到你們討論的都是一樣的話題,都看了6、7年了。這可能是我最后一次在job版寫長文了,年底可能在職場版再寫一篇長文,我的論壇生活就差不多over了,論壇已經(jīng)不是我們這個(gè)時(shí)代的人的了。 
              
              
            在最后,想對(duì)各位師弟,師妹說的是—— 
            各位師弟,師姐師妹是你們的,offer和銀子也是你們的! 
            各位師妹,師兄師弟是你們的,師姐師妹有時(shí)候也是你們的,offer和戶口也是你們的! 
            看到不少公司今年開了40多萬的offer,你們可以一定要努力,一定給北郵爭光,戶口和50萬的offer都要給母校拿一堆回來! 
              
            祝大家找工作順利,11月才剛開始,后續(xù)的路還長。論壇以后靠你們啦!找完工作了別忘了給你們的師弟師妹們多分享點(diǎn)經(jīng)驗(yàn)
             
            posted @ 2011-11-06 11:31 IT菜鳥 閱讀(196) | 評(píng)論 (0)編輯 收藏

            2011年10月19日 #

            16.將vector和string傳給遺留的API
            *vector ,const char* c ,用 &vector[0]即可
            *string ,string.c_str()

            17.使用“交換技巧”來修正過剩容器
            *vector<Contestant> vec(contestants).swap(contestants)

            18.避免使用vector<bool>
            兩個(gè)問題
            *它不是一個(gè)STL容器,它并不容納bool
            如果C是一個(gè)T類型的對(duì)象的容器,且C支持operator[],那么以下代碼必須能夠通過編譯
            T* p= &c[0] //無論operator[]返回什么,都可以用這個(gè)地址初始化一個(gè)T*
            但是vector<bool>中做了優(yōu)化,里面存放的是bit值
            deque內(nèi)部內(nèi)存不是連續(xù)的,但里面存的是bool值
            還有一個(gè)bitse可解決這個(gè)問題

            19.了解相等和等價(jià)的區(qū)別
            *相等的概念是基于operator== ,等價(jià)的概念基于operator<
            20.為指針的關(guān)聯(lián)容器指定比較類型
            關(guān)聯(lián)容器對(duì) 相同 的定義是等價(jià)

            21.永遠(yuǎn)讓比較函數(shù)對(duì)相等的值返回false

            22.避免原地修改set和multiset的鍵

             

            posted @ 2011-10-19 18:29 IT菜鳥 閱讀(249) | 評(píng)論 (0)編輯 收藏

            2011年10月12日 #

            條款10 和 11不太懂,以后再看看

            條款10,注意分配器的協(xié)定和約束
            如果要自定義分配器
            *把你的分配器做成一個(gè)模板,帶有模板參數(shù)T,代表你要分配的內(nèi)存的對(duì)象類型
            *提供pointer和reference的typedef,但總是讓pointer是T* reference是T&
            *通常,分配器不能有非靜態(tài)的數(shù)據(jù)成員
            *記得應(yīng)該傳給分配器的allocate成員函數(shù)需要分配的對(duì)象個(gè)數(shù)而不是字節(jié)數(shù),也應(yīng)該記得這些函數(shù)返回T*指針,即時(shí)還沒有T對(duì)象被構(gòu)造
            *一定要提供標(biāo)準(zhǔn)容器依賴的內(nèi)嵌rebind模板

            條款12,對(duì)STL容器線程安全性的期待現(xiàn)實(shí)一些

            template<typename Container>
            class Lock
            {
            public:
             Lock(
            const Container container): c( containner ){
              getMutexFor( c );
             }

             
            ~Lock(){
              releaseMutexFor( c );
             }

            private:
            const Container& c;

            }
            ;

            vector
            <int> v;
            {
             Lock
            < vect< int > > lock( v );
             vector
            <int>::iterator first5( find(v.begin() v.end(), 5));
             
            if( first5 != v.end()){
              
            *first5 = 0;
             }

            }


             

            posted @ 2011-10-12 17:51 IT菜鳥 閱讀(369) | 評(píng)論 (0)編輯 收藏

            2011年10月11日 #

            條款九,在刪除選項(xiàng)中仔細(xì)選擇
            *在一個(gè)標(biāo)準(zhǔn)STL容器中去掉值為1963的對(duì)象,若是一個(gè)連續(xù)內(nèi)存容器,最好的方法是erase-remove
            c.erase ( remove( c.begin(), c.end(), 1963 ), c.end() );//當(dāng)C時(shí)vector,string ,deque時(shí),這是一處特定值得元素的最佳方法
            *當(dāng)C是標(biāo)準(zhǔn)關(guān)聯(lián)容器的時(shí)候(map, set)使用任何叫做remove的東西都是完全錯(cuò)誤的
            而應(yīng)該直接采用c.erase(1963)對(duì)數(shù)的高效時(shí)間
            *但如果操作是從C中除去每個(gè)有特定值的物體
            bool bandValue(int x)
            對(duì)于序列容器(vector, string,deque,list)我們要做的只是把每個(gè)remove替換為remove_if然后就OK了
            c.erase( remove_if(c.begin(), c.end(), badValue), c.end())//vector,string,deque
            c.remove_if( badValue ) //list
            對(duì)于標(biāo)準(zhǔn)關(guān)聯(lián)容器,
            AssocContainner<int> c;
            for(AssoContainer<int>::iterator i = c.begin();
            i!= c.end(); )
            {
             if(badValue(*i)) c.erase(i++);
             else ++i;
            }
            posted @ 2011-10-11 16:24 IT菜鳥 閱讀(193) | 評(píng)論 (0)編輯 收藏

            條款五,盡量使用區(qū)間成員函數(shù)代替他們的單元素兄弟
            *對(duì)于所有標(biāo)準(zhǔn)序列容器(vector, string, deque, 和list)都有效,無論何時(shí)你必須完全替代一個(gè)容器的內(nèi)容,你就應(yīng)該想到賦值
            *insert,每次都必須移動(dòng)為新元素騰出空間
            *序列容器erase時(shí)返回迭代器,而關(guān)聯(lián)容器返回空

            條款六,警惕C++最令人惱怒的解析
            int g( double pf() ) pf其實(shí)是一個(gè)指針
            int g( double() );同上,函數(shù)名省略
            int g( double x) == int g( double (x) )

            條款七, 當(dāng)時(shí)用new得指針的容器時(shí),記得在銷毀容器前delete那些指針
            *這樣的代碼造成內(nèi)存泄露

            void doSomething()
            {
             vector
            <Widget*> vwp;
             
            for(int i =0 ; i < SOME_MAGIC_NUMBER; ++i)
             
            {
              vwp.push_back(
            new Widget);
             }

             
            //使用完畢的時(shí)候,vwp內(nèi)的Widget對(duì)象沒有釋放
            }



            最簡單的實(shí)現(xiàn)方法是

            void doSomething()
            {
             
            for(vector<Widget*>::iterator i = vwp.begin(); != vwp.end(); ++i)
             
            {
              delete 
            *i;
             }

            }



            這樣的問題是for循環(huán)代碼多余for_each,但沒有使用for_each簡單明了
            另一個(gè)問題是這段代碼不是異常安全的

            簡潔不考慮異常的方法

            struct DeleteObject{
             template
            <typename T>
             
            void operator()(const T* ptr) const
             
            {
              delete prt;
             }

            }
            ;
            void doSomething()
            {
             deque
            <SpecialString*> dssp;
             for_each( dssp.begin(), dssp.end(), DeleteObject());
            }


            void doSomething()
            {
             typedef boost::shar_ptr
            <Widget> SPW;
             vector
            <SPW> vwp;
             
            for(int i = 0; i <SOME_MAGIC_NUMBER; ++i)
             
            {
              vwp.push_back( SPW(
            new Widget));
             }

            }



             

            posted @ 2011-10-11 15:03 IT菜鳥 閱讀(338) | 評(píng)論 (0)編輯 收藏

            2011年10月10日 #

            條款三 使容器里對(duì)象的拷貝量輕而正確
            *容器中的對(duì)象都是拷貝來拷貝出去
            *容器的拷貝要注意基類的切割問題
            *使拷貝更高效、正確,且對(duì)分割問題免疫的簡單的方式是建立指針的容器而不是對(duì)象的容器,最好是智能指針

            條款四 容器用empty來代替檢查size()是否為0
            *理由很簡單,對(duì)于所有的標(biāo)準(zhǔn)容器,empty是一個(gè)常數(shù)時(shí)間的操作,但對(duì)于一些List實(shí)現(xiàn),size()花費(fèi)線性時(shí)間
            *list的size花費(fèi)線性時(shí)間是因?yàn)闉榱俗宻plice變?yōu)槌?shù)時(shí)間,這是一個(gè)讓哪個(gè)函數(shù)實(shí)現(xiàn)最高效率的問題

            所以對(duì)于所有容器來說,用empty()而不是size()==0

            posted @ 2011-10-10 18:31 IT菜鳥 閱讀(249) | 評(píng)論 (0)編輯 收藏

            條款二 小心對(duì)容器無關(guān)的幻想

            UML 的幾點(diǎn) 總結(jié),不一定對(duì)。。
            關(guān)聯(lián)一般保存的都是指針
            聚合一般保存的都是對(duì)象
            依賴一般都是參數(shù)
            關(guān)聯(lián)都是我主動(dòng)方指向被動(dòng)方

            一般來講不要這么寫:

            class Widget{};
            vector
            <Widget> vw;
            Widget bestWidget;
            vector
            <Widget>::iterator i = find(vw.begin(), vw.end(),bestWidget);


             

            要這么寫

             

            class Widget{};
            typedef vector
            <Widget> WidgetContainer;
            typedef WidgetContainer::iterator WCIterator;
            WidgetContainer cw;
            Widget bestWidget;
            WCIterator i 
            = find(cw.begin(), cw.end(),bestWidget);

             

            posted @ 2011-10-10 17:43 IT菜鳥 閱讀(252) | 評(píng)論 (0)編輯 收藏

            條款一 仔細(xì)選擇你的容器
            *vector<char>可以作為string的替代品
            *vector list deque ,vector是一種可以默認(rèn)使用的序列類型,當(dāng)很頻繁的對(duì)序列中進(jìn)行插入和刪除的時(shí)候應(yīng)該用list,大部分發(fā)生在尾部的話用deque這種數(shù)據(jù)結(jié)構(gòu)
            *連續(xù)內(nèi)存容器和基于節(jié)點(diǎn)的容器的區(qū)別
            連續(xù)容器vector/string/deque在一個(gè)或者多個(gè)內(nèi)存塊中保存它們的元素,如果新元素被插入或者已存元素被刪除,其他在同一個(gè)內(nèi)存塊中的元素必須向上或者向下移動(dòng)來為新元素提供空間或者填充原來被刪除的元素所占的空間,這種移動(dòng)影響了效率。
            基于節(jié)點(diǎn)的list,插入或者刪除的時(shí)候不需要移動(dòng)
            *序列容器在任意位置插入一個(gè)新元素,關(guān)聯(lián)容器不可以
            *容器中的數(shù)據(jù)的內(nèi)存布局需要兼容C嗎,如果是,那只能用vector
            *查找速度,散列容器》排序的vector>標(biāo)準(zhǔn)的關(guān)聯(lián)容器
            *需要可靠的插入和刪除的能力,如果是需要使用基于節(jié)點(diǎn)的容器
            *需要迭代器、指針、引用的實(shí)效次數(shù)減少到最小,如果是,使用介于節(jié)點(diǎn)的容器,一般來說,在連續(xù)容器上的插入和刪除會(huì)使所有指向容器的迭代器指針和引用實(shí)效
            posted @ 2011-10-10 13:33 IT菜鳥 閱讀(359) | 評(píng)論 (0)編輯 收藏

            2011年9月23日 #

            務(wù)器結(jié)構(gòu)探討 -- 最簡單的結(jié)構(gòu) 

              所謂服務(wù)器結(jié)構(gòu),也就是如何將服務(wù)器各部分合理地安排,以實(shí)現(xiàn)最初的功能需求。所以,結(jié)構(gòu)本無所謂正確與錯(cuò)誤;當(dāng)然,優(yōu)秀的結(jié)構(gòu)更有助于系統(tǒng)的搭建,對(duì)系統(tǒng)的可擴(kuò)展性及可維護(hù)性也有更大的幫助。 

              好的結(jié)構(gòu)不是一蹴而就的,而且每個(gè)設(shè)計(jì)者心中的那把尺都不相同,所以這個(gè)優(yōu)秀結(jié)構(gòu)的定義也就沒有定論。在這里,我們不打算對(duì)現(xiàn)有游戲結(jié)構(gòu)做評(píng)價(jià),而是試著從頭開始搭建一個(gè)我們需要的MMOG結(jié)構(gòu)。 

              對(duì)于一個(gè)最簡單的游戲服務(wù)器來說,它只需要能夠接受來自客戶端的連接請(qǐng)求,然后處理客戶端在游戲世界中的移動(dòng)及交互,也即游戲邏輯處理即可。如果我們把這兩項(xiàng)功能集成到一個(gè)服務(wù)進(jìn)程中,則最終的結(jié)構(gòu)很簡單: 

              client ----- server 

              嗯,太簡單了點(diǎn),這樣也敢叫服務(wù)器結(jié)構(gòu)?好吧,現(xiàn)在我們來往里面稍稍加點(diǎn)東西,讓它看起來更像是服務(wù)器結(jié)構(gòu)一些。 

              一般來說,我們?cè)诮尤胗螒蚍?wù)器的時(shí)候都會(huì)要提供一個(gè)帳號(hào)和密碼,驗(yàn)證通過后才能進(jìn)入。關(guān)于為什么要提供用戶名和密碼才能進(jìn)入的問題我們這里不打算做過多討論,云風(fēng)曾對(duì)此也提出過類似的疑問,并給出了只用一個(gè)標(biāo)識(shí)串就能進(jìn)入的設(shè)想,有興趣的可以去看看他們的討論。但不管是采用何種方式進(jìn)入,照目前看來我們的服務(wù)器起碼得提供一個(gè)帳號(hào)驗(yàn)證的功能。 

              我們把觀察點(diǎn)先集中在一個(gè)大區(qū)內(nèi)。在大多數(shù)情況下,一個(gè)大區(qū)內(nèi)都會(huì)有多組游戲服,也就是多個(gè)游戲世界可供選擇。簡單點(diǎn)來實(shí)現(xiàn),我們完全可以拋棄這個(gè)大區(qū)的概念,認(rèn)為一個(gè)大區(qū)也就是放在同一個(gè)機(jī)房的多臺(tái)服務(wù)器組,各服務(wù)器組間沒有什么關(guān)系。這樣,我們可為每組服務(wù)器單獨(dú)配備一臺(tái)登錄服。最后的結(jié)構(gòu)圖應(yīng)該像這樣: 

              loginServer   gameServer 
                 |           / 
                 |         / 
                 client 

              該結(jié)構(gòu)下的玩家操作流程為,先選擇大區(qū),再選擇大區(qū)下的某臺(tái)服務(wù)器,即某個(gè)游戲世界,點(diǎn)擊進(jìn)入后開始帳號(hào)驗(yàn)證過程,驗(yàn)證成功則進(jìn)入了該游戲世界。但是,如果玩家想要切換游戲世界,他只能先退出當(dāng)前游戲世界,然后進(jìn)入新的游戲世界重新進(jìn)行帳號(hào)驗(yàn)證。 

              早期的游戲大都采用的是這種結(jié)構(gòu),有些游戲在實(shí)現(xiàn)時(shí)采用了一些技術(shù)手段使得在切換游戲服時(shí)不需要再次驗(yàn)證帳號(hào),但整體結(jié)構(gòu)還是未做改變。 

              該結(jié)構(gòu)存在一個(gè)服務(wù)器資源配置的問題。因?yàn)榈卿浄幚淼倪壿嬒鄬?duì)來說比較簡單,就是將玩家提交的帳號(hào)和密碼送到數(shù)據(jù)庫進(jìn)行驗(yàn)證,和生成會(huì)話密鑰發(fā)送給游戲服和客戶端,操作完成后連接就會(huì)立即斷開,而且玩家在以后的游戲過程中不會(huì)再與登錄服打任何交道。這樣處理短連接的過程使得系統(tǒng)在大多數(shù)情況下都是比較空閑的,但是在某些時(shí)候,由于請(qǐng)求比較密集,比如開新服的時(shí)候,登錄服的負(fù)載又會(huì)比較大,甚至?xí)幚聿贿^來。 

              另外在實(shí)際的游戲運(yùn)營中,有些游戲世界很火爆,而有些游戲世界卻非常冷清,甚至沒有多少人玩的情況也是很常見的。所以,我們能否更合理地配置登錄服資源,使得整個(gè)大區(qū)內(nèi)的登錄服可以共享就成了下一步改進(jìn)的目標(biāo)。 

            服務(wù)器結(jié)構(gòu)探討 -- 登錄服的負(fù)載均衡 

              回想一下我們?cè)谕鎤ow時(shí)的操作流程:運(yùn)行wow.exe進(jìn)入游戲后,首先就會(huì)要求我們輸入用戶名和密碼進(jìn)行驗(yàn)證,驗(yàn)證成功后才會(huì)出來游戲世界列表,之后是排隊(duì)進(jìn)入游戲世界,開始游戲... 

              可以看到跟前面的描述有個(gè)很明顯的不同,那就是要先驗(yàn)證帳號(hào)再選擇游戲世界。這種結(jié)構(gòu)也就使得登錄服不是固定配備給個(gè)游戲世界,而是全區(qū)共有的。 

              我們可以試著從實(shí)際需求的角度來考慮一下這個(gè)問題。正如我們之前所描述過的那樣,登錄服在大多數(shù)情況下都是比較空閑的,也許我們的一個(gè)擁有20個(gè)游戲世界的大區(qū)僅僅使用10臺(tái)或更少的登錄服即可滿足需求。而當(dāng)在開新區(qū)的時(shí)候,或許要配備40臺(tái)登錄服才能應(yīng)付那如潮水般涌入的玩家登錄請(qǐng)求。所以,登錄服在設(shè)計(jì)上應(yīng)該能滿足這種動(dòng)態(tài)增刪的需求,我們可以在任何時(shí)候?yàn)榇髤^(qū)增加或減少登錄服的部署。 

              當(dāng)然,在這里也不會(huì)存在要求添加太多登錄服的情況。還是拿開新區(qū)的情況來說,即使新增加登錄服滿足了玩家登錄的請(qǐng)求,游戲世界服的承載能力依然有限,玩家一樣只能在排隊(duì)系統(tǒng)中等待,或者是進(jìn)入到游戲世界中導(dǎo)致大家都卡。 

              另外,當(dāng)我們?cè)谠黾踊蛞瞥卿浄臅r(shí)候不應(yīng)該需要對(duì)游戲世界服有所改動(dòng),也不會(huì)要求重啟世界服,當(dāng)然也不應(yīng)該要求客戶端有什么更新或者修改,一切都是在背后自動(dòng)完成。 

              最后,有關(guān)數(shù)據(jù)持久化的問題也在這里考慮一下。一般來說,使用現(xiàn)有的商業(yè)數(shù)據(jù)庫系統(tǒng)比自己手工技術(shù)先進(jìn)要明智得多。我們需要持久化的數(shù)據(jù)有玩家的帳號(hào)及密碼,玩家創(chuàng)建的角色相關(guān)信息,另外還有一些游戲世界全局共有數(shù)據(jù)也需要持久化。 

              好了,需求已經(jīng)提出來了,現(xiàn)在來考慮如何將其實(shí)現(xiàn)。 

              對(duì)于負(fù)載均衡來說,已有了成熟的解決方案。一般最常用,也最簡單部署的應(yīng)該是基于DNS的負(fù)載均衡系統(tǒng)了,其通過在DNS中為一個(gè)域名配置多個(gè)IP地址來實(shí)現(xiàn)。最新的DNS服務(wù)已實(shí)現(xiàn)了根據(jù)服務(wù)器系統(tǒng)狀態(tài)來實(shí)現(xiàn)的動(dòng)態(tài)負(fù)載均衡,也就是實(shí)現(xiàn)了真正意義上的負(fù)載均衡,這樣也就有效地解決了當(dāng)某臺(tái)登錄服當(dāng)機(jī)后,DNS服務(wù)器不能立即做出反應(yīng)的問題。當(dāng)然,如果找不到這樣的解決方案,自己從頭打造一個(gè)也并不難。而且,通過DNS來實(shí)現(xiàn)的負(fù)載均衡已經(jīng)包含了所做的修改對(duì)登錄服及客戶端的透明。 

              而對(duì)于數(shù)據(jù)庫的應(yīng)用,在這種結(jié)構(gòu)下,登錄服及游戲世界服都會(huì)需要連接數(shù)據(jù)庫。從數(shù)據(jù)庫服務(wù)器的部署上來說,可以將帳號(hào)和角色數(shù)據(jù)都放在一個(gè)中心數(shù)據(jù)庫中,也可分為兩個(gè)不同的庫分別來處理,基到從物理上分到兩臺(tái)不同的服務(wù)器上去也行。 

              但是對(duì)于不同的游戲世界來說,其角色及游戲內(nèi)數(shù)據(jù)都是互相獨(dú)立的,所以一般情況下也就為每個(gè)游戲世界單獨(dú)配備一臺(tái)數(shù)據(jù)庫服務(wù)器,以減輕數(shù)據(jù)庫的壓力。所以,整體的服務(wù)器結(jié)構(gòu)應(yīng)該是一個(gè)大區(qū)有一臺(tái)帳號(hào)數(shù)據(jù)庫服務(wù)器,所有的登錄服都連接到這里。而每個(gè)游戲世界都有自己的游戲數(shù)據(jù)庫服務(wù)器,只允許本游戲世界內(nèi)的服務(wù)器連接。 

              最后,我們的服務(wù)器結(jié)構(gòu)就像這樣: 

                           大區(qū)服務(wù)器        
                      /     |       \ 
                        /       |        \ 
                        登錄服1   登錄服2   世界服1   世界服2 
                     \         |         |       |   
                      \       |         |         | 
                      帳號(hào)數(shù)據(jù)庫         DBS     DBS 

              這里既然討論到了大區(qū)及帳號(hào)數(shù)據(jù)庫,所以順帶也說一下關(guān)于激活大區(qū)的概念。wow中一共有八個(gè)大區(qū),我們想要進(jìn)入某個(gè)大區(qū)游戲之前,必須到官網(wǎng)上激活這個(gè)區(qū),這是為什么呢? 

              一般來說,在各個(gè)大區(qū)帳號(hào)數(shù)據(jù)庫之上還有一個(gè)總的帳號(hào)數(shù)據(jù)庫,我們可以稱它為中心數(shù)據(jù)庫。比如我們?cè)诠倬W(wǎng)上注冊(cè)了一個(gè)帳號(hào),這時(shí)帳號(hào)數(shù)據(jù)是只保存在中心數(shù)據(jù)庫上的。而當(dāng)我們要到一區(qū)去創(chuàng)建角色開始游戲的時(shí)候,在一區(qū)的帳號(hào)數(shù)據(jù)庫中并沒有我們的帳號(hào)數(shù)據(jù),所以,我們必須先到官網(wǎng)上做一次激活操作。這個(gè)激活的過程也就是從中心庫上把我們的帳號(hào)數(shù)據(jù)拷貝到所要到的大區(qū)帳號(hào)數(shù)據(jù)庫中。 

            服務(wù)器結(jié)構(gòu)探討 -- 簡單的世界服實(shí)現(xiàn) 

              討論了這么久我們一直都還沒有進(jìn)入游戲世界服務(wù)器內(nèi)部,現(xiàn)在就讓我們來窺探一下里面的結(jié)構(gòu)吧。 

              對(duì)于現(xiàn)在大多數(shù)MMORPG來說,游戲服務(wù)器要處理的基本邏輯有移動(dòng)、聊天、技能、物品、任務(wù)和生物等,另外還有地圖管理與消息廣播來對(duì)其他高級(jí)功能做支撐。如縱隊(duì)、好友、公會(huì)、戰(zhàn)場和副本等,這些都是通過基本邏輯功能組合或擴(kuò)展而成。 

              在所有這些基礎(chǔ)邏輯中,與我們要討論的服務(wù)器結(jié)構(gòu)關(guān)系最緊密的當(dāng)屬地圖管理方式。決定了地圖的管理方式也就決定了我們的服務(wù)器結(jié)構(gòu),我們?nèi)匀幌葟淖詈唵蔚膶?shí)現(xiàn)方式開始說起。 

              回想一下我們?cè)鴳?zhàn)斗過無數(shù)個(gè)夜晚的暗黑破壞神,整個(gè)暗黑的世界被分為了若干個(gè)獨(dú)立的小地圖,當(dāng)我們?cè)诘貓D間穿越時(shí),一般都要經(jīng)過一個(gè)叫做傳送門的裝置。世界中有些地圖間雖然在地理上是直接相連的,但我們發(fā)現(xiàn)其游戲內(nèi)部的邏輯卻是完全隔離的。可以這樣認(rèn)為,一塊地圖就是一個(gè)獨(dú)立的數(shù)據(jù)處理單元。 

              既然如此,我們就把每塊地圖都當(dāng)作是一臺(tái)獨(dú)立的服務(wù)器,他提供了在這塊地圖上游戲時(shí)的所有邏輯功能,至于內(nèi)部結(jié)構(gòu)如何劃分我們暫不理會(huì),先把他當(dāng)作一個(gè)黑盒子吧。 

              當(dāng)兩個(gè)人合作做一件事時(shí),我們可以以對(duì)等的關(guān)系相互協(xié)商著來做,而且一般也都不會(huì)有什么問題。當(dāng)人數(shù)增加到三個(gè)時(shí),我們對(duì)等的合作關(guān)系可能會(huì)有些復(fù)雜,因?yàn)槲覀兠總€(gè)人都同時(shí)要與另兩個(gè)人合作協(xié)商。正如俗語所說的那樣,三個(gè)和尚可能會(huì)碰到?jīng)]水喝的情況。當(dāng)人數(shù)繼續(xù)增加,情況就變得不那么簡單了,我們得需要一個(gè)管理者來對(duì)我們的工作進(jìn)行分工、協(xié)調(diào)。游戲的地圖服務(wù)器之間也是這么回事。 

              一般來說,我們的游戲世界不可能會(huì)只有一塊或者兩塊小地圖,那順理成章的,也就需要一個(gè)地圖管理者。先稱它為游戲世界的中心服務(wù)器吧,畢竟是管理者嘛,大家都以它為中心。 

              中心服務(wù)器主要維護(hù)一張地圖ID到地圖服務(wù)器地址的映射表。當(dāng)我們要進(jìn)入某張地圖時(shí),會(huì)從中心服上取得該地圖的IP和port告訴客戶端,客戶端主動(dòng)去連接,這樣進(jìn)入他想要去的游戲地圖。在整個(gè)游戲過程中,客戶端始終只會(huì)與一臺(tái)地圖服務(wù)器保持連接,當(dāng)要切換地圖的時(shí)候,在獲取到新地圖的地址后,會(huì)先與當(dāng)前地圖斷開連接,再進(jìn)入新的地圖,這樣保證玩家數(shù)據(jù)在服務(wù)器上只有一份。 

              我們來看看結(jié)構(gòu)圖是怎樣的: 

                          中心服務(wù)器 
                       /       \         \ 
                     /         \         \ 
                   登錄服     地圖1     地圖2   地圖n 
                     \         |         /       / 
                       \       |         /       / 
                            客戶端 

              很簡單,不是嗎。但是簡單并不表示功能上會(huì)有什么損失,簡單也更不能表示游戲不能賺錢。早期不少游戲也確實(shí)采用的就是這種簡單結(jié)構(gòu)。 

            服務(wù)器結(jié)構(gòu)探討 -- 繼續(xù)世界服 

              都已經(jīng)看出來了,這種每切換一次地圖就要重新連接服務(wù)器的方式實(shí)在是不夠優(yōu)雅,而且在實(shí)際游戲運(yùn)營中也發(fā)現(xiàn),地圖切換導(dǎo)致的卡號(hào),復(fù)制裝備等問題非常多,這里完全就是一個(gè)事故多發(fā)地段,如何避免這種頻繁的連接操作呢? 

              最直接的方法就是把那個(gè)圖倒轉(zhuǎn)過來就行了。客戶端只需要連接到中心服上,所有到地圖服務(wù)器的數(shù)據(jù)都由中心服來轉(zhuǎn)發(fā)。很完美的解決方案,不是嗎? 

              這種結(jié)構(gòu)在實(shí)際的部署中也遇到了一些挑戰(zhàn)。對(duì)于一般的MMORPG服務(wù)器來說,單臺(tái)服務(wù)器的承載量平均在2000左右,如果你的服務(wù)器很不幸地只能帶1000人,沒關(guān)系,不少游戲都是如此;如果你的服務(wù)器上跑了3000多玩家依然比較流暢,那你可以自豪地告訴你的策劃,多設(shè)計(jì)些大量消耗服務(wù)器資源的玩法吧,比如大型國戰(zhàn)、公會(huì)戰(zhàn)爭等。 

              2000人,似乎我們的策劃朋友們不大愿意接受這個(gè)數(shù)字。我們將地圖服務(wù)器分開來原來也是想將負(fù)載分開,以多帶些客戶端,現(xiàn)在要所有的連接都從中心服上轉(zhuǎn)發(fā),那連接數(shù)又遇到單臺(tái)服務(wù)器的可最大承載量的瓶頸了。 

              這里有必要再解釋下這個(gè)數(shù)字。我知道,有人一定會(huì)說,才帶2000人,那是你水平不行,我隨便寫個(gè)TCP服務(wù)器都可帶個(gè)五六千連接。問題恰恰在于你是隨便寫的,而MMORPG的服務(wù)器是復(fù)雜設(shè)計(jì)的。如果一個(gè)演示socket API用的echo服務(wù)器就能滿足MMOG服務(wù)器的需求,那寫服務(wù)器該是件多么愜意的事啊。 

              但我們所遇到的事實(shí)是,服務(wù)器收到一個(gè)移動(dòng)包后,要向周圍所有人廣播,而不是echo服務(wù)器那樣簡單的回應(yīng);服務(wù)器在收到一個(gè)連接斷開通知時(shí)要向很多人通知玩家退出事件,并將該玩家的資料寫入數(shù)據(jù)庫,而不是echo服務(wù)器那樣什么都不需要做;服務(wù)器在收到一個(gè)物品使用請(qǐng)求包后要做一系列的邏輯判斷以檢查玩家有沒有作弊;服務(wù)器上還啟動(dòng)著很多定時(shí)器用來更新游戲世界的各種狀態(tài)...... 

              其實(shí)這么一比較,我們也看出資源消耗的所在了:服務(wù)器上大量的復(fù)雜的邏輯處理。再回過頭來看看我們想要實(shí)現(xiàn)的結(jié)構(gòu),我們既想要有一個(gè)唯一的入口,使得客戶端不用頻繁改變連接,又希望這個(gè)唯一入口的負(fù)載不會(huì)太大,以致于接受不了多少連接。 

              仔細(xì)看一看這個(gè)需求,我們想要的僅僅只是一臺(tái)管理連接的服務(wù)器,并不打算讓他承擔(dān)太多的游戲邏輯。既然如此,那五六千個(gè)連接也還有滿足我們的要求。至少在現(xiàn)在來說,一個(gè)游戲世界內(nèi),也就是一組服務(wù)器內(nèi)同時(shí)有五六千個(gè)在線的玩家還是件讓人很興奮的事。事實(shí)上,在大多數(shù)游戲的大部分時(shí)間里,這個(gè)數(shù)字也是很讓人眼紅的。 

              什么?你說夢幻、魔獸還有史先生的那個(gè)什么征途遠(yuǎn)不止這么點(diǎn)人了!噢,我說的是大多數(shù),是大多數(shù),不包括那些明星。你知道大陸現(xiàn)在有多少游戲在運(yùn)營嗎?或許你又該說,我們不該在一開始就把自己的目標(biāo)定的太低!好吧,我們還是先不談這個(gè)。 

              繼續(xù)我們的結(jié)構(gòu)討論。一般來說,我們把這臺(tái)負(fù)責(zé)連接管理的服務(wù)器稱為網(wǎng)關(guān)服務(wù)器,因?yàn)閮?nèi)部的數(shù)據(jù)都要通過這個(gè)網(wǎng)關(guān)才能出去,不過從這臺(tái)服務(wù)器提供的功能來看,稱其為反向代理服務(wù)器可能更合適。我們也不在這個(gè)名字上糾纏了,就按大家通用的叫法,還是稱他為網(wǎng)關(guān)服務(wù)器吧。 

              網(wǎng)關(guān)之后的結(jié)構(gòu)我們依然可以采用之前描述的方案,只是,似乎并沒有必要為每一個(gè)地圖都開一個(gè)獨(dú)立的監(jiān)聽端口了。我們可以試著對(duì)地圖進(jìn)行一些劃分,由一個(gè)Master Server來管理一些更小的Zone Server,玩家通過網(wǎng)關(guān)連接到Master Server上,而實(shí)際與地圖有關(guān)的邏輯是分派給更小的Zone Server去處理。 

              最后的結(jié)構(gòu)看起來大概是這樣的: 

                     Zone Server         Zone Server 
                             \             / 
                             \           / 
                             Master Server           Master Server 
                                 /       \                   / 
                               /         \                 / 
                     Gateway Server         \               / 
                         |         \         \             / 
                         |         \         \           / 
                         |               Center Server 
                         | 
                         | 
                       Client 

            服務(wù)器結(jié)構(gòu)探討 -- 最終的結(jié)構(gòu) 

              如果我們就此打住,可能馬上就會(huì)有人要嗤之以鼻了,就這點(diǎn)古董級(jí)的技術(shù)也敢出來現(xiàn)。好吧,我們還是把之前留下的問題拿出來解決掉吧。 

              一般來說,當(dāng)某一部分能力達(dá)不到我們的要求時(shí),最簡單的解決方法就是在此多投入一點(diǎn)資源。既然想要更多的連接數(shù),那就再加一臺(tái)網(wǎng)關(guān)服務(wù)器吧。新增加了網(wǎng)關(guān)服后需要在大區(qū)服上做相應(yīng)的支持,或者再簡單點(diǎn),有一臺(tái)主要的網(wǎng)關(guān)服,當(dāng)其負(fù)載較高時(shí),主動(dòng)將新到達(dá)的連接重定向到其他網(wǎng)關(guān)服上。 

              而對(duì)于游戲服來說,有一臺(tái)還是多臺(tái)網(wǎng)關(guān)服是沒有什么區(qū)別的。每個(gè)代表客戶端玩家的對(duì)象內(nèi)部都保留一個(gè)代表其連接的對(duì)象,消息廣播時(shí)要求每個(gè)玩家對(duì)象使用自己的連接對(duì)象發(fā)送數(shù)據(jù)即可,至于連接是在什么地方,那是完全透明的。當(dāng)然,這只是一種簡單的實(shí)現(xiàn),也是普通使用的一種方案,如果后期想對(duì)消息廣播做一些優(yōu)化的話,那可能才需要多考慮一下。 

              既然說到了優(yōu)化,我們也稍稍考慮一下現(xiàn)在結(jié)構(gòu)下可能采用的優(yōu)化方案。 

              首先是當(dāng)前的Zone Server要做的事情太多了,以至于他都處理不了多少連接。這其中最消耗系統(tǒng)資源的當(dāng)屬生物的AI處理了,尤其是那些復(fù)雜的尋路算法,所以我們可以考慮把這部分AI邏輯獨(dú)立出來,由一臺(tái)單獨(dú)的AI服務(wù)器來承擔(dān)。 

              然后,我們可以試著把一些與地圖數(shù)據(jù)無關(guān)的公共邏輯放到Master Server上去實(shí)現(xiàn),這樣Zone Server上只保留了與地圖數(shù)據(jù)緊密相關(guān)的邏輯,如生物管理,玩家移動(dòng)和狀態(tài)更新等。 

              還有聊天處理邏輯,這部分與游戲邏輯沒有任何關(guān)聯(lián),我們也完全可以將其獨(dú)立出來,放到一臺(tái)單獨(dú)的聊天服務(wù)器上去實(shí)現(xiàn)。 

              最后是數(shù)據(jù)庫了,為了減輕數(shù)據(jù)庫的壓力,提高數(shù)據(jù)請(qǐng)求的響應(yīng)速度,我們可以在數(shù)據(jù)庫之前建立一個(gè)數(shù)據(jù)庫緩存服務(wù)器,將一些常用數(shù)據(jù)緩存在此,服務(wù)器與數(shù)據(jù)庫的通信都要通過這臺(tái)服務(wù)器進(jìn)行代理。緩存的數(shù)據(jù)會(huì)定時(shí)的寫入到后臺(tái)數(shù)據(jù)庫中。 

              好了,做完這些優(yōu)化我們的服務(wù)器結(jié)構(gòu)大體也就定的差不多了,暫且也不再繼續(xù)深入,更細(xì)化的內(nèi)容等到各個(gè)部分實(shí)現(xiàn)的時(shí)候再探討。 

              好比我們?nèi)タ匆粓鐾頃?huì),舞臺(tái)上演員們按著預(yù)定的節(jié)目單有序地上演著,但這就是整場晚會(huì)的全部嗎?顯然不止,在幕后還有太多太多的人在忙碌著,甚至在晚會(huì)前和晚會(huì)后都有。我們的游戲服務(wù)器也如此。 

              在之前描述的部分就如同舞臺(tái)上的演員,是我們能直接看到的,幕后的工作人員我們也來認(rèn)識(shí)一下。 

              現(xiàn)實(shí)中有警察來維護(hù)秩序,游戲中也如此,這就是我們常說的GM。GM可以采用跟普通玩家一樣的拉入方式來進(jìn)入游戲,當(dāng)然權(quán)限會(huì)比普通玩家高一些,也可以提供一臺(tái)GM服務(wù)器專門用來處理GM命令,這樣可以有更高的安全性,GM服一般接在中心服務(wù)器上。 

              在以時(shí)間收費(fèi)的游戲中,我們還需要一臺(tái)計(jì)費(fèi)的服務(wù)器,這臺(tái)服務(wù)器一般接在網(wǎng)關(guān)服務(wù)器上,注冊(cè)玩家登錄和退出事件以記錄玩家的游戲時(shí)間。 

              任何為用戶提供服務(wù)的地方都會(huì)有日志記錄,游戲服務(wù)器當(dāng)然也不例外。從記錄玩家登錄的時(shí)間,地址,機(jī)器信息到游戲過程中的每一項(xiàng)操作都可以作為日志記錄下來,以備查錯(cuò)及數(shù)據(jù)挖掘用。至于搜集玩家機(jī)器資料所涉及到的法律問題不是我們?cè)摽紤]的。 

              差不多就這么多了吧,接下來我們會(huì)按照這個(gè)大致的結(jié)構(gòu)來詳細(xì)討論各部分的實(shí)現(xiàn)。 

            服務(wù)器結(jié)構(gòu)探討 -- 一點(diǎn)雜談 

              再強(qiáng)調(diào)一下,服務(wù)器結(jié)構(gòu)本無所謂好壞,只有是否適合自己。我們?cè)谇懊嫣接懥艘恍┰诂F(xiàn)在的游戲中見到過的結(jié)構(gòu),并盡我所知地分析了各自存在的一些問題和可以做的一些改進(jìn),希望其中沒有謬誤,如果能給大家也帶來些啟發(fā)那自然更好。 

              突然發(fā)現(xiàn)自己一旦羅嗦起來還真是沒完沒了。接下來先說說我在開發(fā)中遇到過的一些困惑和一基礎(chǔ)問題探討吧,這些問題可能有人與我一樣,也曾遇到過,或者正在被困擾中,而所要探討的這些基礎(chǔ)問題向來也是爭論比較多的,我們也不評(píng)價(jià)其中的好與壞,只做簡單的描述。 

              首先是服務(wù)器操作系統(tǒng),linux與windows之爭隨處可見,其實(shí)在大多數(shù)情況下這不是我們所能決定的,似乎各大公司也基本都有了自己的傳統(tǒng),如網(wǎng)易的freebsd,騰訊的linux等。如果真有權(quán)利去選擇的話,選自己最熟悉的吧。 

              決定了OS也就基本上確定了網(wǎng)絡(luò)IO模型,windows上的IOCP和linux下的epool,或者直接使用現(xiàn)有的網(wǎng)絡(luò)框架,如ACE和asio等,其他還有些商業(yè)的網(wǎng)絡(luò)庫在國內(nèi)的使用好像沒有見到,不符合中國國情嘛。:) 

              然后是網(wǎng)絡(luò)協(xié)議的選擇,以前的選擇大多傾向于UDP,為了可靠傳輸一般自己都會(huì)在上面實(shí)現(xiàn)一層封裝,而現(xiàn)在更普通的是直接采用本身就很可靠的TCP,或者TCP與UDP的混用。早期選擇UDP的主要原因還是帶寬限制,現(xiàn)在寬帶普通的情況下TCP比UDP多出來的一點(diǎn)點(diǎn)開銷與開發(fā)的便利性相比已經(jīng)不算什么了。當(dāng)然,如果已有了成熟的可靠UDP庫,那也可以繼續(xù)使用著。 

              還有消息包格式的定義,這個(gè)曾在云風(fēng)的blog上展開過激烈的爭論。消息包格式定義包括三段,包長、消息碼和包體,爭論的焦點(diǎn)在于應(yīng)該是消息碼在前還是包長在前,我們也把這個(gè)當(dāng)作是信仰問題吧,有興趣的去云風(fēng)的blog上看看,論論。 

              另外早期有些游戲的包格式定義是以特殊字符作分隔的,這樣一個(gè)好處是其中某個(gè)包出現(xiàn)錯(cuò)誤后我們的游戲還能繼續(xù)。但實(shí)際上,我覺得這是完全沒有必要的,真要出現(xiàn)這樣的錯(cuò)誤,直接斷開這個(gè)客戶端的連接可能更安全。而且,以特殊字符做分隔的消息包定義還加大了一點(diǎn)點(diǎn)網(wǎng)絡(luò)數(shù)據(jù)量。 

              最后是一個(gè)純技術(shù)問題,有關(guān)socket連接數(shù)的最大限制。開始學(xué)習(xí)網(wǎng)絡(luò)編程的時(shí)候我犯過這樣的錯(cuò)誤,以為port的定義為unsigned short,所以想當(dāng)然的認(rèn)為服務(wù)器的最大連接數(shù)為65535,這會(huì)是一個(gè)硬性的限制。而實(shí)際上,一個(gè)socket描述符在windows上的定義是unsigned int,因此要有限制那也是四十多億,放心好了。 

              在服務(wù)器上port是監(jiān)聽用的,想象這樣一種情況,web server在80端口上監(jiān)聽,當(dāng)一個(gè)連接到來時(shí),系統(tǒng)會(huì)為這個(gè)連接分配一個(gè)socket句柄,同時(shí)與其在80端口上進(jìn)行通訊;當(dāng)另一個(gè)連接到來時(shí),服務(wù)器仍然在80端口與之通信,只是分配的socket句柄不一樣。這個(gè)socket句柄才是描述每個(gè)連接的唯一標(biāo)識(shí)。按windows網(wǎng)絡(luò)編程第二版上的說法,這個(gè)上限值配置影響。 

              好了,廢話說完了,下一篇,我們開始進(jìn)入登錄服的設(shè)計(jì)吧。 

            登錄服的設(shè)計(jì) -- 功能需求 

              正如我們?cè)谇懊嬖懻撨^的,登錄服要實(shí)現(xiàn)的功能相當(dāng)簡單,就是帳號(hào)驗(yàn)證。為了便于描述,我們暫不引入那些討論過的優(yōu)化手段,先以最簡單的方式實(shí)現(xiàn),另外也將基本以mangos的代碼作為參考來進(jìn)行描述。 

              想象一下帳號(hào)驗(yàn)證的實(shí)現(xiàn)方法,最容易的那就是把用戶輸入的明文用帳號(hào)和密碼直接發(fā)給登錄服,服務(wù)器根據(jù)帳號(hào)從數(shù)據(jù)庫中取出密碼,與用戶輸入的密碼相比較。 

              這個(gè)方法存在的安全隱患實(shí)在太大,明文的密碼傳輸太容易被截獲了。那我們?cè)囍趥鬏斨跋燃右幌旅埽瑸榱朔?wù)器能進(jìn)行密碼比較,我們應(yīng)該采用一個(gè)可逆的加密算法,在服務(wù)器端把這個(gè)加密后的字串還原為原始的明文密碼,然后與數(shù)據(jù)庫密碼進(jìn)行比較。既然是一個(gè)可逆的過程,那外掛制作者總有辦法知道我們的加密過程,所以,這個(gè)方法仍不夠安全。 

              哦,如果我們只是希望密碼不可能被還原出來,那還不容易嗎,使用一個(gè)不可逆的散列算法就行了。用戶在登錄時(shí)發(fā)送給服務(wù)器的是明文的帳號(hào)和經(jīng)散列后的不可逆密碼串,服務(wù)器取出密碼后也用同樣的算法進(jìn)行散列后再進(jìn)行比較。比如,我們就用使用最廣泛的md5算法吧。噢,不要管那個(gè)王小云的什么論文,如果我真有那么好的運(yùn)氣,早中500w了,還用在這考慮該死的服務(wù)器設(shè)計(jì)嗎? 

              似乎是一個(gè)很完美的方案,外掛制作者再也偷不到我們的密碼了。慢著,外掛偷密碼的目的是什么?是為了能用我們的帳號(hào)進(jìn)游戲!如果我們總是用一種固定的算法來對(duì)密碼做散列,那外掛只需要記住這個(gè)散列后的字串就行了,用這個(gè)做密碼就可以成功登錄。 

              嗯,這個(gè)問題好解決,我們不要用固定的算法進(jìn)行散列就是了。只是,問題在于服務(wù)器與客戶端采用的散列算法得出的字串必須是相同的,或者是可驗(yàn)證其是否匹配的。很幸運(yùn)的是,偉大的數(shù)學(xué)字們?cè)缇蜑槲覀儨?zhǔn)備好了很多優(yōu)秀的這類算法,而且經(jīng)理論和實(shí)踐都證明他們也確實(shí)是足夠安全的。 

              這其中之一是一個(gè)叫做SRP的算法,全稱叫做Secure Remote Password,即安全遠(yuǎn)程密碼。wow使用的是第6版,也就是SRP6算法。有關(guān)其中的數(shù)學(xué)證明,如果有人能向我解釋清楚,并能讓我真正弄明白的話,我將非常感激。不過其代碼實(shí)現(xiàn)步驟倒是并不復(fù)雜,mangos中的代碼也還算清晰,我們也不再贅述。 

              登錄服除了帳號(hào)驗(yàn)證外還得提供另一項(xiàng)功能,就是在玩家的帳號(hào)驗(yàn)證成功后返回給他一個(gè)服務(wù)器列表讓他去選擇。這個(gè)列表的狀態(tài)要定時(shí)刷新,可能有新的游戲世界開放了,也可能有些游戲世界非常不幸地停止運(yùn)轉(zhuǎn)了,這些狀態(tài)的變化都要盡可能及時(shí)地讓玩家知道。不管發(fā)生了什么事,用戶都有權(quán)利知道,特別是對(duì)于付過費(fèi)的用戶來說,我們不該藏著掖著,不是嗎? 

              這個(gè)游戲世界列表的功能將由大區(qū)服來提供,具體的結(jié)構(gòu)我們?cè)谥耙裁枋鲞^,這里暫不做討論。登錄服將從大區(qū)服上獲取到的游戲世界列表發(fā)給已驗(yàn)證通過的客戶端即可。好了,登錄服要實(shí)現(xiàn)的功能就這些,很簡單,是吧。 

              確實(shí)是太簡單了,不過簡單的結(jié)構(gòu)正好更適合我們來看一看游戲服務(wù)器內(nèi)部的模塊結(jié)構(gòu),以及一些服務(wù)器共有組件的實(shí)現(xiàn)方法。這就留作下一篇吧。 

            服務(wù)器公共組件實(shí)現(xiàn) -- mangos的游戲主循環(huán) 

              當(dāng)閱讀一項(xiàng)工程的源碼時(shí),我們大概會(huì)選擇從main函數(shù)開始,而當(dāng)開始一項(xiàng)新的工程時(shí),第一個(gè)寫下的函數(shù)大多也是main。那我們就先來看看,游戲服務(wù)器代碼實(shí)現(xiàn)中,main函數(shù)都做了些什么。 

              由于我在讀技術(shù)文章時(shí)最不喜看到的就是大段大段的代碼,特別是那些直接Ctrl+C再Ctrl+V后未做任何修改的代碼,用句時(shí)髦的話說,一點(diǎn)技術(shù)含量都沒有!所以在我們今后所要討論的內(nèi)容中,盡量會(huì)避免出現(xiàn)直接的代碼,在有些地方確實(shí)需要代碼來表述時(shí),也將會(huì)選擇使用偽碼。 

              先從mangos的登錄服代碼開始。mangos的登錄服是一個(gè)單線程的結(jié)構(gòu),雖然在數(shù)據(jù)庫連接中可以開啟一個(gè)獨(dú)立的線程,但這個(gè)線程也只是對(duì)無返回結(jié)果的執(zhí)行類SQL做緩沖,而對(duì)需要有返回結(jié)果的查詢類SQL還是在主邏輯線程中阻塞調(diào)用的。 

              登錄服中唯一的這一個(gè)線程,也就是主循環(huán)線程對(duì)監(jiān)聽的socket做select操作,為每個(gè)連接進(jìn)來的客戶端讀取其上的數(shù)據(jù)并立即進(jìn)行處理,直到服務(wù)器收到SIGABRT或SIGBREAK信號(hào)時(shí)結(jié)束。 

              所以,mangos登錄服主循環(huán)的邏輯,也包括后面游戲服的邏輯,主循環(huán)的關(guān)鍵代碼其實(shí)是在SocketHandler中,也就是那個(gè)Select函數(shù)中。檢查所有的連接,對(duì)新到來的連接調(diào)用OnAccept方法,有數(shù)據(jù)到來的連接則調(diào)用OnRead方法,然后socket處理器自己定義對(duì)接收到的數(shù)據(jù)如何處理。 

              很簡單的結(jié)構(gòu),也比較容易理解。 


              只是,在對(duì)性能要求比較高的服務(wù)器上,select一般不會(huì)是最好的選擇。如果我們使用windows平臺(tái),那IOCP將是首選;如果是linux,epool將是不二選擇。我們也不打算討論基于IOCP或是基于epool的服務(wù)器實(shí)現(xiàn),如果僅僅只是要實(shí)現(xiàn)服務(wù)器功能,很簡單的幾個(gè)API調(diào)用即可,而且網(wǎng)上已有很多好的教程;如果是要做一個(gè)成熟的網(wǎng)絡(luò)服務(wù)器產(chǎn)品,不是我?guī)灼唵蔚募夹g(shù)介紹文章所能達(dá)到。 

              另外,在服務(wù)器實(shí)現(xiàn)上,網(wǎng)絡(luò)IO與邏輯處理一般會(huì)放在不同的線程中,以免耗時(shí)較長的IO過程阻塞住了需要立即反應(yīng)的游戲邏輯。 

              數(shù)據(jù)庫的處理也類似,會(huì)使用異步的方式,也是避免耗時(shí)的查詢過程將游戲服務(wù)器主循環(huán)阻塞住。想象一下,因某個(gè)玩家上線而發(fā)起的一次數(shù)據(jù)庫查詢操作導(dǎo)致服務(wù)器內(nèi)所有在線玩家都卡住不動(dòng)將是多么恐怖的一件事! 

              另外還有一些如事件、腳本、消息隊(duì)列、狀態(tài)機(jī)、日志和異常處理等公共組件,我們也會(huì)在接下來的時(shí)間里進(jìn)行探討。 

            服務(wù)器公共組件實(shí)現(xiàn) -- 繼續(xù)來說主循環(huán) 

              前面我們只簡單了解了下mangos登錄服的程序結(jié)構(gòu),也發(fā)現(xiàn)了一些不足之處,現(xiàn)在我們就來看看如何提供一個(gè)更好的方案。 

              正如我們?cè)懻撨^的,為了游戲主邏輯循環(huán)的流暢運(yùn)行,所有比較耗時(shí)的IO操作都會(huì)分享到單獨(dú)的線程中去做,如網(wǎng)絡(luò)IO,數(shù)據(jù)庫IO和日志IO等。當(dāng)然,也有把這些分享到單獨(dú)的進(jìn)程中去做的。 

              另外對(duì)于大多數(shù)服務(wù)器程序來說,在運(yùn)行時(shí)都是作為精靈進(jìn)程或服務(wù)進(jìn)程的,所以我們并不需要服務(wù)器能夠處理控制臺(tái)用戶輸入,我們所要處理的數(shù)據(jù)來源都來自網(wǎng)絡(luò)。 

              這樣,主邏輯循環(huán)所要做的就是不停要取消息包來處理,當(dāng)然這些消息包不僅有來自客戶端的玩家操作數(shù)據(jù)包,也有來自GM服務(wù)器的管理命令,還包括來自數(shù)據(jù)庫查詢線程的返回結(jié)果消息包。這個(gè)循環(huán)將一直持續(xù),直到收到一個(gè)通知服務(wù)器關(guān)閉的消息包。 

              主邏輯循環(huán)的結(jié)構(gòu)還是很簡單的,復(fù)雜的部分都在如何處理這些消息包的邏輯上。我們可以用一段簡單的偽碼來描述這個(gè)循環(huán)過程: 

                while (Message* msg = getMessage()) 
                { 
                  if (msg為服務(wù)器關(guān)閉消息) 
                    break; 
                  處理msg消息; 
                } 

              這里就有一個(gè)問題需要探討了,在getMessage()的時(shí)候,我們應(yīng)該去哪里取消息?前面我們考慮過,至少會(huì)有三個(gè)消息來源,而我們還討論過,這些消息源的IO操作都是在獨(dú)立的線程中進(jìn)行的,我們這里的主線程不應(yīng)該直接去那幾處消息源進(jìn)行阻塞式的IO操作。 

              很簡單,讓那些獨(dú)立的IO線程在接收完數(shù)據(jù)后自己送過來就是了。好比是,我這里提供了一個(gè)倉庫,有很多的供貨商,他們有貨要給我的時(shí)候只需要交到倉庫,然后我再到倉庫去取就是了,這個(gè)倉庫也就是消息隊(duì)列。消息隊(duì)列是一個(gè)普通的隊(duì)列實(shí)現(xiàn),當(dāng)然必須要提供多線程互斥訪問的安全性支持,其基本的接口定義大概類似這樣: 

                IMessageQueue 
                { 
                  void putMessage(Message*); 
                  Message* getMessage(); 
                } 

              網(wǎng)絡(luò)IO,數(shù)據(jù)庫IO線程把整理好的消息包都加入到主邏輯循環(huán)線程的這個(gè)消息隊(duì)列中便返回。有關(guān)消息隊(duì)列的實(shí)現(xiàn)和線程間消息的傳遞在ACE中有比較完全的代碼實(shí)現(xiàn)及描述,還有一些使用示例,是個(gè)很好的參考。 

              這樣的話,我們的主循環(huán)就很清晰了,從主線程的消息隊(duì)列中取消息,處理消息,再取下一條消息...... 

            服務(wù)器公共組件實(shí)現(xiàn) -- 消息隊(duì)列 

              既然說到了消息隊(duì)列,那我們繼續(xù)來稍微多聊一點(diǎn)吧。 

              我們所能想到的最簡單的消息隊(duì)列可能就是使用stl的list來實(shí)現(xiàn)了,即消息隊(duì)列內(nèi)部維護(hù)一個(gè)list和一個(gè)互斥鎖,putMessage時(shí)將message加入到隊(duì)列尾,getMessage時(shí)從隊(duì)列頭取一個(gè)message返回,同時(shí)在getMessage和putMessage之前都要求先獲取鎖資源。 

              實(shí)現(xiàn)雖然簡單,但功能是絕對(duì)滿足需求的,只是性能上可能稍稍有些不盡如人意。其最大的問題在頻繁的鎖競爭上。 

              對(duì)于如何減少鎖競爭次數(shù)的優(yōu)化方案,Ghost Cheng提出了一種。提供一個(gè)隊(duì)列容器,里面有多個(gè)隊(duì)列,每個(gè)隊(duì)列都可固定存放一定數(shù)量的消息。網(wǎng)絡(luò)IO線程要給邏輯線程投遞消息時(shí),會(huì)從隊(duì)列容器中取一個(gè)空隊(duì)列來使用,直到將該隊(duì)列填滿后再放回容器中換另一個(gè)空隊(duì)列。而邏輯線程取消息時(shí)是從隊(duì)列容器中取一個(gè)有消息的隊(duì)列來讀取,處理完后清空隊(duì)列再放回到容器中。 

              這樣便使得只有在對(duì)隊(duì)列容器進(jìn)行操作時(shí)才需要加鎖,而IO線程和邏輯線程在操作自己當(dāng)前使用的隊(duì)列時(shí)都不需要加鎖,所以鎖競爭的機(jī)會(huì)大大減少了。 

              這里為每個(gè)隊(duì)列設(shè)了個(gè)最大消息數(shù),看來好像是打算只有當(dāng)IO線程寫滿隊(duì)列時(shí)才會(huì)將其放回到容器中換另一個(gè)隊(duì)列。那這樣有時(shí)也會(huì)出現(xiàn)IO線程未寫滿一個(gè)隊(duì)列,而邏輯線程又沒有數(shù)據(jù)可處理的情況,特別是當(dāng)數(shù)據(jù)量很少時(shí)可能會(huì)很容易出現(xiàn)。Ghost Cheng在他的描述中沒有講到如何解決這種問題,但我們可以先來看看另一個(gè)方案。 

              這個(gè)方案與上一個(gè)方案基本類似,只是不再提供隊(duì)列容器,因?yàn)樵谶@個(gè)方案中只使用了兩個(gè)隊(duì)列,arthur在他的一封郵件中描述了這個(gè)方案的實(shí)現(xiàn)及部分代碼。兩個(gè)隊(duì)列,一個(gè)給邏輯線程讀,一個(gè)給IO線程用來寫,當(dāng)邏輯線程讀完隊(duì)列后會(huì)將自己的隊(duì)列與IO線程的隊(duì)列相調(diào)換。所以,這種方案下加鎖的次數(shù)會(huì)比較多一些,IO線程每次寫隊(duì)列時(shí)都要加鎖,邏輯線程在調(diào)換隊(duì)列時(shí)也需要加鎖,但邏輯線程在讀隊(duì)列時(shí)是不需要加鎖的。 

              雖然看起來鎖的調(diào)用次數(shù)是比前一種方案要多很多,但實(shí)際上大部分鎖調(diào)用都是不會(huì)引起阻塞的,只有在邏輯線程調(diào)換隊(duì)列的那一瞬間可能會(huì)使得某個(gè)線程阻塞一下。另外對(duì)于鎖調(diào)用過程本身來說,其開銷是完全可以忽略的,我們所不能忍受的僅僅是因?yàn)殒i調(diào)用而引起的阻塞而已。 

              兩種方案都是很優(yōu)秀的優(yōu)化方案,但也都是有其適用范圍的。Ghost Cheng的方案因?yàn)樘峁┝硕鄠€(gè)隊(duì)列,可以使得多個(gè)IO線程可以總工程師的,互不干擾的使用自己的隊(duì)列,只是還有一個(gè)遺留問題我們還不了解其解決方法。arthur的方案很好的解決了上一個(gè)方案遺留的問題,但因?yàn)橹挥幸粋€(gè)寫隊(duì)列,所以當(dāng)想要提供多個(gè)IO線程時(shí),線程間互斥地寫入數(shù)據(jù)可能會(huì)增大競爭的機(jī)會(huì),當(dāng)然,如果只有一個(gè)IO線程那將是非常完美的。 

            服務(wù)器公共組件實(shí)現(xiàn) -- 環(huán)形緩沖區(qū) 

              消息隊(duì)列鎖調(diào)用太頻繁的問題算是解決了,另一個(gè)讓人有些苦惱的大概是這太多的內(nèi)存分配和釋放操作了。頻繁的內(nèi)存分配不但增加了系統(tǒng)開銷,更使得內(nèi)存碎片不斷增多,非常不利于我們的服務(wù)器長期穩(wěn)定運(yùn)行。也許我們可以使用內(nèi)存池,比如SGI STL中附帶的小內(nèi)存分配器。但是對(duì)于這種按照嚴(yán)格的先進(jìn)先出順序處理的,塊大小并不算小的,而且塊大小也并不統(tǒng)一的內(nèi)存分配情況來說,更多使用的是一種叫做環(huán)形緩沖區(qū)的方案,mangos的網(wǎng)絡(luò)代碼中也有這么一個(gè)東西,其原理也是比較簡單的。 

              就好比兩個(gè)人圍著一張圓形的桌子在追逐,跑的人被網(wǎng)絡(luò)IO線程所控制,當(dāng)寫入數(shù)據(jù)時(shí),這個(gè)人就往前跑;追的人就是邏輯線程,會(huì)一直往前追直到追上跑的人。如果追上了怎么辦?那就是沒有數(shù)據(jù)可讀了,先等會(huì)兒唄,等跑的人向前跑幾步了再追,總不能讓游戲沒得玩了吧。那要是追的人跑的太慢,跑的人轉(zhuǎn)了一圈過來反追上追的人了呢?那您也先歇會(huì)兒吧。要是一直這么反著追,估計(jì)您就只能換一個(gè)跑的更快的追逐者了,要不這游戲還真沒法玩下去。 

              前面我們特別強(qiáng)調(diào)了,按照嚴(yán)格的先進(jìn)先出順序進(jìn)行處理,這是環(huán)形緩沖區(qū)的使用必須遵守的一項(xiàng)要求。也就是,大家都得遵守規(guī)定,追的人不能從桌子上跨過去,跑的人當(dāng)然也不允許反過來跑。至于為什么,不需要多做解釋了吧。 

              環(huán)形緩沖區(qū)是一項(xiàng)很好的技術(shù),不用頻繁的分配內(nèi)存,而且在大多數(shù)情況下,內(nèi)存的反復(fù)使用也使得我們能用更少的內(nèi)存塊做更多的事。 

              在網(wǎng)絡(luò)IO線程中,我們會(huì)為每一個(gè)連接都準(zhǔn)備一個(gè)環(huán)形緩沖區(qū),用于臨時(shí)存放接收到的數(shù)據(jù),以應(yīng)付半包及粘包的情況。在解包及解密完成后,我們會(huì)將這個(gè)數(shù)據(jù)包復(fù)制到邏輯線程消息隊(duì)列中,如果我們只使用一個(gè)隊(duì)列,那這里也將會(huì)是個(gè)環(huán)形緩沖區(qū),IO線程往里寫,邏輯線程在后面讀,互相追逐。可要是我們使用了前面介紹的優(yōu)化方案后,可能這里便不再需要環(huán)形緩沖區(qū)了,至少我們并不再需要他們是環(huán)形的了。因?yàn)槲覀儗?duì)同一個(gè)隊(duì)列不再會(huì)出現(xiàn)同時(shí)讀和寫的情況,每個(gè)隊(duì)列在寫滿后交給邏輯線程去讀,邏輯線程讀完后清空隊(duì)列再交給IO線程去寫,一段固定大小的緩沖區(qū)即可。沒關(guān)系,這么好的技術(shù),在別的地方一定也會(huì)用到的。 

            服務(wù)器公共組件實(shí)現(xiàn) -- 發(fā)包的方式 

              前面一直都在說接收數(shù)據(jù)時(shí)的處理方法,我們應(yīng)該用專門的IO線程,接收到完整的消息包后加入到主線程的消息隊(duì)列,但是主線程如何發(fā)送數(shù)據(jù)還沒有探討過。 

              一般來說最直接的方法就是邏輯線程什么時(shí)候想發(fā)數(shù)據(jù)了就直接調(diào)用相關(guān)的socket API發(fā)送,這要求服務(wù)器的玩家對(duì)象中保存其連接的socket句柄。但是直接send調(diào)用有時(shí)候有會(huì)存在一些問題,比如遇到系統(tǒng)的發(fā)送緩沖區(qū)滿而阻塞住的情況,或者只發(fā)送了一部分?jǐn)?shù)據(jù)的情況也時(shí)有發(fā)生。我們可以將要發(fā)送的數(shù)據(jù)先緩存一下,這樣遇到未發(fā)送完的,在邏輯線程的下一次處理時(shí)可以接著再發(fā)送。 

              考慮數(shù)據(jù)緩存的話,那這里這可以有兩種實(shí)現(xiàn)方式了,一是為每個(gè)玩家準(zhǔn)備一個(gè)緩沖區(qū),另外就是只有一個(gè)全局的緩沖區(qū),要發(fā)送的數(shù)據(jù)加入到全局緩沖區(qū)的時(shí)候同時(shí)要指明這個(gè)數(shù)據(jù)是發(fā)到哪個(gè)socket的。如果使用全局緩沖區(qū)的話,那我們可以再進(jìn)一步,使用一個(gè)獨(dú)立的線程來處理數(shù)據(jù)發(fā)送,類似于邏輯線程對(duì)數(shù)據(jù)的處理方式,這個(gè)獨(dú)立發(fā)送線程也維護(hù)一個(gè)消息隊(duì)列,邏輯線程要發(fā)數(shù)據(jù)時(shí)也只是把數(shù)據(jù)加入到這個(gè)隊(duì)列中,發(fā)送線程循環(huán)取包來執(zhí)行send調(diào)用,這時(shí)的阻塞也就不會(huì)對(duì)邏輯線程有任何影響了。 

              采用第二種方式還可以附帶一個(gè)優(yōu)化方案。一般對(duì)于廣播消息而言,發(fā)送給周圍玩家的數(shù)據(jù)都是完全相同的,我們?nèi)绻捎媒o每個(gè)玩家一個(gè)緩沖隊(duì)列的方式,這個(gè)數(shù)據(jù)包將需要拷貝多份,而采用一個(gè)全局發(fā)送隊(duì)列時(shí),我們只需要把這個(gè)消息入隊(duì)一次,同時(shí)指明該消息包是要發(fā)送給哪些socket的即可。有關(guān)該優(yōu)化的說明在云風(fēng)描述其連接服務(wù)器實(shí)現(xiàn)的blog文章中也有講到,有興趣的可以去閱讀一下。 

            服務(wù)器公共組件實(shí)現(xiàn) -- 狀態(tài)機(jī) 

              有關(guān)State模式的設(shè)計(jì)意圖及實(shí)現(xiàn)就不從設(shè)計(jì)模式中摘抄了,我們只來看看游戲服務(wù)器編程中如何使用State設(shè)計(jì)模式。 

              首先還是從mangos的代碼開始看起,我們注意到登錄服在處理客戶端發(fā)來的消息時(shí)用到了這樣一個(gè)結(jié)構(gòu)體: 

              struct AuthHandler 
              { 
                eAuthCmd cmd; 
                uint32 status; 
                bool (AuthSocket::*handler)(void); 
              }; 

              該結(jié)構(gòu)體定義了每個(gè)消息碼的處理函數(shù)及需要的狀態(tài)標(biāo)識(shí),只有當(dāng)前狀態(tài)滿足要求時(shí)才會(huì)調(diào)用指定的處理函數(shù),否則這個(gè)消息碼的出現(xiàn)是不合法的。這個(gè)status狀態(tài)標(biāo)識(shí)的定義是一個(gè)宏,有兩種有效的標(biāo)識(shí),STATUS_CONNECTED和STATUS_AUTHED,也就是未認(rèn)證通過和已認(rèn)證通過。而這個(gè)狀態(tài)標(biāo)識(shí)的改變是在運(yùn)行時(shí)進(jìn)行的,確切的說是在收到某個(gè)消息并正確處理完后改變的。 

              我們?cè)賮砜纯丛O(shè)計(jì)模式中對(duì)State模式的說明,其中關(guān)于State模式適用情況里有一條,當(dāng)操作中含有龐大的多分支的條件語句,且這些分支依賴于該對(duì)象的狀態(tài),這個(gè)狀態(tài)通常用一個(gè)或多個(gè)枚舉變量表示。 

              描述的情況與我們這里所要處理的情況是如此的相似,也許我們可以試一試。那再看看State模式提供的解決方案是怎樣的,State模式將每一個(gè)條件分支放入一個(gè)獨(dú)立的類中。 

              由于這里的兩個(gè)狀態(tài)標(biāo)識(shí)只區(qū)分出了兩種狀態(tài),所以,我們僅需要兩個(gè)獨(dú)立的類,用以表示兩種狀態(tài)即可。然后,按照State模式的描述,我們還需要一個(gè)Context類,也就是狀態(tài)機(jī)管理類,用以管理當(dāng)前的狀態(tài)類。稍作整理,大概的代碼會(huì)類似這樣: 

              狀態(tài)基類接口: 
              StateBase 
              { 
                void Enter() = 0; 
                void Leave() = 0; 
                void Process(Message* msg) = 0; 
              }; 

              狀態(tài)機(jī)基類接口: 
              MachineBase 
              { 
                void ChangeState(StateBase* state) = 0; 

                StateBase* m_curState; 
              }; 

              我們的邏輯處理類會(huì)從MachineBase派生,當(dāng)取出數(shù)據(jù)包后交給當(dāng)前狀態(tài)處理,前面描述的兩個(gè)狀態(tài)類從StateBase派生,每個(gè)狀態(tài)類只處理該狀態(tài)標(biāo)識(shí)下需要處理的消息。當(dāng)要進(jìn)行狀態(tài)轉(zhuǎn)換時(shí),調(diào)用MachineBase的ChangeState()方法,顯示地告訴狀態(tài)機(jī)管理類自己要轉(zhuǎn)到哪一個(gè)狀態(tài)。所以,狀態(tài)類內(nèi)部需要保存狀態(tài)機(jī)管理類的指針,這個(gè)可以在狀態(tài)類初始化時(shí)傳入。具體的實(shí)現(xiàn)細(xì)節(jié)就不做過多描述了。 

              使用狀態(tài)機(jī)雖然避免了復(fù)雜的判斷語句,但也引入了新的麻煩。當(dāng)我們?cè)谶M(jìn)行狀態(tài)轉(zhuǎn)換時(shí),可能會(huì)需要將一些現(xiàn)場數(shù)據(jù)從老狀態(tài)對(duì)象轉(zhuǎn)移到新狀態(tài)對(duì)象,這需要在定義接口時(shí)做一下考慮。如果不希望執(zhí)行拷貝,那么這里公有的現(xiàn)場數(shù)據(jù)也可放到狀態(tài)機(jī)類中,只是這樣在使用時(shí)可能就不那么優(yōu)雅了。 

              正如同在設(shè)計(jì)模式中所描述的,所有的模式都是已有問題的另一種解決方案,也就是說這并不是唯一的解決方案。放到我們今天討論的State模式中,就拿登錄服所處理的兩個(gè)狀態(tài)來說,也許用mangos所采用的遍歷處理函數(shù)的方法可能更簡單,但當(dāng)系統(tǒng)中的狀態(tài)數(shù)量增多,狀態(tài)標(biāo)識(shí)也變多的時(shí)候,State模式就顯得尤其重要了。 

              比如在游戲服務(wù)器上玩家的狀態(tài)管理,還有在實(shí)現(xiàn)NPC人工智能時(shí)的各種狀態(tài)管理,這些就留作以后的專題吧。 

            服務(wù)器公共組件 -- 事件與信號(hào) 

            關(guān)于這一節(jié),這幾天已經(jīng)打了好幾遍草稿,總覺得說不清楚,也不好組織這些內(nèi)容,但是打鐵要趁熱,為避免熱情消退,先整理一點(diǎn)東西放這,好繼續(xù)下面的主題,以后如果有機(jī)會(huì)再回來完善吧。本節(jié)內(nèi)容欠考慮,希望大家多給點(diǎn)意見。 

            有些類似于QT中的event與signal,我將一些動(dòng)作請(qǐng)求消息定義為事件,而將狀態(tài)改變消息定義為信號(hào)。比如在QT應(yīng)用程序中,用戶的一次鼠標(biāo)點(diǎn)擊會(huì)產(chǎn)生一個(gè)鼠標(biāo)點(diǎn)擊事件加入到事件隊(duì)列中,當(dāng)處理此事件時(shí)可能會(huì)導(dǎo)致某個(gè)按鈕控件產(chǎn)生一個(gè)clicked()信號(hào)。 

            對(duì)應(yīng)到我們的服務(wù)器上的一個(gè)例子,玩家登錄時(shí)會(huì)發(fā)給服務(wù)器一個(gè)請(qǐng)求登錄的數(shù)據(jù)包,服務(wù)器可將其當(dāng)作一個(gè)用戶登錄事件,該事件處理完后可能會(huì)產(chǎn)生一個(gè)用戶已登錄信號(hào)。 

            這樣,與QT類似,對(duì)于事件我們可以重定義其處理方法,甚至過濾掉某些事件使其不被處理,但對(duì)于信號(hào)我們只是收到了一個(gè)通知,有些類似于Observe模式中的觀察者,當(dāng)收到更新通知時(shí),我們只能更新自己的狀態(tài),對(duì)剛剛發(fā)生的事件我不已不能做任何影響。 

            仔細(xì)來看,事件與信號(hào)其實(shí)并無多大差別,從我們對(duì)其需求上來說,都只要能注冊(cè)事件或信號(hào)響應(yīng)函數(shù),在事件或信號(hào)產(chǎn)生時(shí)能夠被通知到即可。但有一項(xiàng)區(qū)別在于,事件處理函數(shù)的返回值是有意義的,我們要根據(jù)這個(gè)返回值來確定是否還要繼續(xù)事件的處理,比如在QT中,事件處理函數(shù)如果返回true,則這個(gè)事件處理已完成,QApplication會(huì)接著處理下一個(gè)事件,而如果返回false,那么事件分派函數(shù)會(huì)繼續(xù)向上尋找下一個(gè)可以處理該事件的注冊(cè)方法。信號(hào)處理函數(shù)的返回值對(duì)信號(hào)分派器來說是無意義的。 

            簡單點(diǎn)說,就是我們可以為事件定義過濾器,使得事件可以被過濾。這一功能需求在游戲服務(wù)器上是到處存在的。 

            關(guān)于事件和信號(hào)機(jī)制的實(shí)現(xiàn),網(wǎng)絡(luò)上的開源訓(xùn)也比較多,比如FastDelegate,sigslot,boost::signal等,其中sigslot還被Google采用,在libjingle的代碼中我們可以看到他是如何被使用的。 

            在實(shí)現(xiàn)事件和信號(hào)機(jī)制時(shí)或許可以考慮用同一套實(shí)現(xiàn),在前面我們就分析過,兩者唯一的區(qū)別僅在于返回值的處理上。 

            另外還有一個(gè)需要我們關(guān)注的問題是事件和信號(hào)處理時(shí)的優(yōu)先級(jí)問題。在QT中,事件因?yàn)槎际桥c窗口相關(guān)的,所以事件回調(diào)時(shí)都是從當(dāng)前窗口開始,一級(jí)一級(jí)向上派發(fā),直到有一個(gè)窗口返回true,截?cái)嗔耸录奶幚頌橹埂?duì)于信號(hào)的處理則比較簡單,默認(rèn)是沒有順序的,如果需要明確的順序,可以在信號(hào)注冊(cè)時(shí)顯示地指明槽的位置。 

            在我們的需求中,因?yàn)闆]有窗口的概念,事件的處理也與信號(hào)類似,對(duì)注冊(cè)過的處理器要按某個(gè)順序依次回調(diào),所以優(yōu)先級(jí)的設(shè)置功能是需要的。 

            最后需要我們考慮的是事件和信號(hào)的處理方式。在QT中,事件使用了一個(gè)事件隊(duì)列來維護(hù),如果事件的處理中又產(chǎn)生了新的事件,那么新的事件會(huì)加入到隊(duì)列尾,直到當(dāng)前事件處理完畢后,QApplication再去隊(duì)列頭取下一個(gè)事件來處理。而信號(hào)的處理方式有些不同,信號(hào)處理是立即回調(diào)的,也就是一個(gè)信號(hào)產(chǎn)生后,他上面所注冊(cè)的所有槽都會(huì)立即被回調(diào)。這樣就會(huì)產(chǎn)生一個(gè)遞歸調(diào)用的問題,比如某個(gè)信號(hào)處理器中又產(chǎn)生了一個(gè)信號(hào),會(huì)使得信號(hào)的處理像一棵樹一樣的展開。我們需要注意的一個(gè)很重要的問題是會(huì)不會(huì)引起循環(huán)調(diào)用。 

            關(guān)于事件機(jī)制的考慮其實(shí)還很多,但都是一些不成熟的想法。在上面的文字中就同時(shí)出現(xiàn)了消息、事件和信號(hào)三個(gè)相近的概念,而在實(shí)際處理中,經(jīng)常發(fā)現(xiàn)三者不知道如何界定的情況,實(shí)際的情況比我在這里描述的要混亂的多。 

            這里也就當(dāng)是挖下一個(gè)坑,希望能夠有所交流。 

            再談登錄服的實(shí)現(xiàn) 

                離我們的登錄服實(shí)現(xiàn)已經(jīng)太遠(yuǎn)了,先拉回來一下。 
                
                關(guān)于登錄服、大區(qū)服及游戲世界服的結(jié)構(gòu)之前已做過探討,這里再把各自的職責(zé)和關(guān)系列一下。 

                    GateWay/WorldServer   GateWay/WodlServer LoginServer LoginServer DNSServer WorldServerMgr 
                            |                     |                     |                 |            | 
                  --------------------------------------------------------------------------------------------- 
                                                         | | | 
                                                         internet 
                                                            | 
                                                          clients 

                其中DNSServer負(fù)責(zé)帶負(fù)載均衡的域名解析服務(wù),返回LoginServer的IP地址給客戶端。WorldServerMgr維護(hù)當(dāng)前大區(qū)內(nèi)的世界服列表,LoginServer會(huì)從這里取世界列表發(fā)給客戶端。LoginServer處理玩家的登錄及世界服選擇請(qǐng)求。GateWay/WorldServer為各個(gè)獨(dú)立的世界服或者通過網(wǎng)關(guān)連接到后面的世界服。 

                在mangos的代碼中,我們注意到登錄服是從數(shù)據(jù)庫中取的世界列表,而在wow官方服務(wù)器中,我們卻會(huì)注意到,這個(gè)世界服列表并不是一開始就固定,而是動(dòng)態(tài)生成的。當(dāng)每周一次的維護(hù)完成之后,我們可以很明顯的看到這個(gè)列表生成的過程。剛開始時(shí),世界列表是空的,慢慢的,世界服會(huì)一個(gè)個(gè)加入進(jìn)來,而這里如果有世界服當(dāng)機(jī),他會(huì)顯示為離線,不會(huì)從列表中刪除。但是當(dāng)下一次服務(wù)器再維護(hù)后,所有的世界服都不存在了,全部重新開始添加。 

                從上面的過程描述中,我們很容易想到利用一個(gè)臨時(shí)的列表來保存世界服信息,這也是我們?cè)黾覹orldServerMgr服務(wù)器的目的所在。GateWay/WorldServer在啟動(dòng)時(shí)會(huì)自動(dòng)向WorldServerMgr注冊(cè)自己,這樣就把自己所代表的游戲世界添加到世界列表中了。類似的,如果DNSServer也可以讓LoginServer自己去注冊(cè),這樣在臨時(shí)LoginServer時(shí)就不需要去改動(dòng)DNSServer的配置文件了。 

                WorldServerMgr內(nèi)部的實(shí)現(xiàn)很簡單,監(jiān)聽一個(gè)固定的端口,接受來自WorldServer的主動(dòng)連接,并檢測其狀態(tài)。這里可以用一個(gè)心跳包來實(shí)現(xiàn)其狀態(tài)的檢測,如果WorldServer的連接斷開或者在規(guī)定時(shí)間內(nèi)未收到心跳包,則將其狀態(tài)更新為離線。另外WorldServerMgr還處理來自LoginServer的列表請(qǐng)求。由于世界列表并不常變化,所以LoginServer沒有必要每次發(fā)送世界列表時(shí)都到WorldServerMgr上去取,LoginServer完全可以自己維護(hù)一個(gè)列表,當(dāng)WorldServerMgr上的列表發(fā)生變化時(shí),WorldServerMgr會(huì)主動(dòng)通知所有的LoginServer也更新一下自己的列表。這個(gè)或許就可以用前面描述過的事件方式,或者就是觀察者模式了。 

                WorldServerMgr實(shí)現(xiàn)所要考慮的內(nèi)容就這些,我們?cè)賮砜纯碙oginServer,這才是我們今天要重點(diǎn)討論的對(duì)象。 

                前面探討一些服務(wù)器公共組件,那我們這里也應(yīng)該試用一下,不能只是停留在理論上。先從狀態(tài)機(jī)開始,前面也說過了,登錄服上的連接會(huì)有兩種狀態(tài),一是帳號(hào)密碼驗(yàn)證狀態(tài),一是服務(wù)器列表選擇狀態(tài),其實(shí)還有另外一個(gè)狀態(tài)我們未曾討論過,因?yàn)樗c我們的登錄過程并無多大關(guān)系,這就是升級(jí)包發(fā)送狀態(tài)。三個(gè)狀態(tài)的轉(zhuǎn)換流程大致為: 

                    LogonState -- 驗(yàn)證成功 -- 版本檢查 -- 版本低于最新值 -- 轉(zhuǎn)到UpdateState 
                                                      | 
                                                       -- 版本等于最新值 -- 轉(zhuǎn)到WorldState 

                這個(gè)版本檢查的和決定下一個(gè)狀態(tài)的過程是在LogonState中進(jìn)行的,下一個(gè)狀態(tài)的選擇是由當(dāng)前狀態(tài)來決定。密碼驗(yàn)證的過程使用了SRP6協(xié)議,具體過程就不多做描述,每個(gè)游戲使用的方式也都不大一樣。而版本檢查的過程就更無值得探討的東西,一個(gè)if-else即可。

                升級(jí)狀態(tài)其實(shí)就是文件傳輸過程,文件發(fā)送完畢后通知客戶端開始執(zhí)行升級(jí)文件并關(guān)閉連接。世界選擇狀態(tài)則提供了一個(gè)列表給客戶端,其中包括了所有游戲世界網(wǎng)關(guān)服務(wù)器的IP、PORT和當(dāng)前負(fù)載情況。如果客戶端一直連接著,則該狀態(tài)會(huì)以每5秒一次的頻率不停刷新列表給客戶端,當(dāng)然是否值得這樣做還是有待商榷。 

                整個(gè)過程似乎都沒有值得探討的內(nèi)容,但是,還沒有完。當(dāng)客戶端選擇了一個(gè)世界之后該怎么辦?wow的做法是,當(dāng)客戶端選擇一個(gè)游戲世界時(shí),客戶端會(huì)主動(dòng)去連接該世界服的IP和PORT,然后進(jìn)入這個(gè)游戲世界。與此同時(shí),與登錄服的連接還沒有斷開,直到客戶端確實(shí)連接上了選定的世界服并且走完了排隊(duì)過程為止。這是一個(gè)很必要的設(shè)計(jì),保證了我們?cè)谝蛞馔馇闆r連接不上世界服或者發(fā)現(xiàn)世界服正在排隊(duì)而想換另外一個(gè)試試時(shí)不會(huì)需要重新進(jìn)行密碼驗(yàn)證。 

                但是我們所要關(guān)注的還不是這些,而是客戶端去連接游戲世界的網(wǎng)關(guān)服時(shí)服務(wù)器該如何識(shí)別我們。打個(gè)比方,有個(gè)不自覺的玩家不遵守游戲規(guī)則,沒有去驗(yàn)證帳號(hào)密碼就直接跑去連接世界服了,就如同一個(gè)不自覺的乘客沒有換登機(jī)牌就直接跑到登機(jī)口一樣。這時(shí),乘務(wù)員會(huì)客氣地告訴你要先換登機(jī)牌,那登機(jī)牌又從哪來?檢票口換的,人家會(huì)先驗(yàn)明你的身份,確認(rèn)后才會(huì)發(fā)給你登機(jī)牌。一樣的處理過程,我們的登錄服在驗(yàn)明客戶端身份后,也會(huì)發(fā)給客戶端一個(gè)登機(jī)牌,這個(gè)登機(jī)牌還有一個(gè)學(xué)名,叫做session key。 

                客戶端拿著這個(gè)session key去世界服網(wǎng)關(guān)處就可正確登錄了嗎?似乎還是有個(gè)疑問,他怎么知道我這個(gè)key是不是造假的?沒辦法,中國的假貨太多,我們不得不到處都考慮假貨的問題。方法很簡單,去找給他登機(jī)牌的那個(gè)檢票員問一下,這張牌是不是他發(fā)的不就得了。可是,那么多的LoginServer,要一個(gè)個(gè)問下來,這效率也太低了,后面排的長隊(duì)一定會(huì)開始叫喚了。那么,LoginServer將這個(gè)key存到數(shù)據(jù)庫中,讓網(wǎng)關(guān)服自己去數(shù)據(jù)庫驗(yàn)證?似乎也是個(gè)可行的方案。 

                如果覺得這樣給數(shù)據(jù)庫帶來了太大的壓力的話,也可以考慮類似WorldServerMgr的做法,用一個(gè)臨時(shí)的列表來保存,甚至可以將這個(gè)列表就保存到WorldServerMgr上,他正好是全區(qū)唯一的。這兩種方案的本質(zhì)并無差別,只是看你愿意將負(fù)載放在哪里。而不管在哪里,這個(gè)查詢的壓力都是有點(diǎn)大的,想想,全區(qū)所有玩家呢。所以,我們也可以試著考慮一種新的方案,一種不需要去全區(qū)唯一一個(gè)入口查詢的方案。 

                那我們將這些session key分開存儲(chǔ)不就得了。一個(gè)可行的方案是,讓任意時(shí)刻只有一個(gè)地方保存一個(gè)客戶端的session key,這個(gè)地方可能是客戶端當(dāng)前正連接著的服務(wù)器,也可以是它正要去連接的服務(wù)器。讓我們來詳細(xì)描述一下這個(gè)過程,客戶端在LoginServer上驗(yàn)證通過時(shí),LoginServer為其生成了本次會(huì)話的session key,但只是保存在當(dāng)前的LoginServer上,不會(huì)存數(shù)據(jù)庫,也不會(huì)發(fā)送給WorldServerMgr。如果客戶端這時(shí)想要去某個(gè)游戲世界,那么他必須先通知當(dāng)前連接的LoginServer要去的服務(wù)器地址,LoginServer將session key安全轉(zhuǎn)移給目標(biāo)服務(wù)器,轉(zhuǎn)移的意思是要確保目標(biāo)服務(wù)器收到了session key,本地保存的要?jiǎng)h除掉。轉(zhuǎn)移成功后LoginServer通知客戶端再去連接目標(biāo)服務(wù)器,這時(shí)目標(biāo)服務(wù)器在驗(yàn)證session key合法性的時(shí)候就不需要去別處查詢了,只在本地保存的session key列表中查詢即可。 

                當(dāng)然了,為了session key的安全,所有的服務(wù)器在收到一個(gè)新的session key后都會(huì)為其設(shè)一個(gè)有效期,在有效期過后還沒來認(rèn)證的,則該session key會(huì)被自動(dòng)刪除。同時(shí),所有服務(wù)器上的session key在連接關(guān)閉后一定會(huì)被刪除,保證一個(gè)session key真正只為一次連接會(huì)話服務(wù)。 

                但是,很顯然的,wow并沒有采用這種方案,因?yàn)榭蛻舳嗽谶x擇世界服時(shí)并沒有向服務(wù)器發(fā)送要求確認(rèn)的消息。wow中的session key應(yīng)該是保存在一個(gè)類似于WorldServerMgr的地方,或者如mangos一樣,就是保存在了數(shù)據(jù)庫中。不管是怎樣一種方式,了解了其過程,代碼實(shí)現(xiàn)都是比較簡單的,我們就不再贅述了。 

            posted @ 2011-09-23 18:21 IT菜鳥 閱讀(457) | 評(píng)論 (1)編輯 收藏

            2011年9月6日 #

            1、倒轉(zhuǎn)單鏈表

                 非遞歸法

                

            1. struct Node  
            2. {  
            3.   int data;  
            4.   Node * next;  
            5. }  
            6. void reverse(Node*& head) {  
            7.   if (head == NULL) {  
            8.      return;  
            9.   }  
            10.   Node * pre, * cur, * nxt;  
            11.   pre = head;  
            12.   cur = head -> next;  
            13.   while (cur != NULL) {  
            14.      pre = cur -> next;  
            15.      pre = cur;  
            16.      cur = nxt;  
            17.      nxt = nxt -> next;  
            18.   }  
            19.   head -> next = NULL;  
            20.   head = pre;  
            21. }  
             

             

             

                 遞歸法

                

            1. Node * reverse(Node * node, Node *&head)  
            2. {  
            3.      if (node == NULL || node -> next == NULL) {  
            4.          head = node;  
            5.          return;  
            6.      }  
            7.      else {  
            8.         Node * nxt = reverse(node -> next, head)  
            9.         node = nxt -> next;  
            10.         return node;  
            11.      }  
            12. }  
            13. 最后要將返回的node的next域設(shè)為NULL。  

             

             

            2、找出倒數(shù)第k個(gè)元素(或中間元素):設(shè)置快慢指針

            3、刪除環(huán)狀單鏈表的一個(gè)節(jié)點(diǎn),只給定指向要?jiǎng)h除節(jié)點(diǎn)的指針

                 思路:無法獲取前一個(gè)指針,那么可刪除下一個(gè)節(jié)點(diǎn),交換當(dāng)前節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)的值即可

            4、兩個(gè)有序鏈表的合并

                 歸并即可

             

            5、判斷單鏈表是否有環(huán)?環(huán)首?

                 是否有環(huán):快慢指針,如果相遇,說明存在環(huán)

                 環(huán)首:可先求出環(huán)長。一個(gè)圓內(nèi)的追及問題,兩次相遇時(shí)慢指針走過的距離即環(huán)長;

                          此時(shí)假設(shè)慢指針已走了i步,則快指針已走了2i步;兩個(gè)指針同時(shí)倒退i步的位置,慢指針退到鏈?zhǔn)祝熘羔樛说絠處,則從這兩個(gè)位置起,指針各走i步既能在環(huán)內(nèi)相遇。

                          于是可設(shè)置兩個(gè)指針,一個(gè)在鏈?zhǔn)滋帲粋€(gè)在i處,步長為1,第一次相遇的節(jié)點(diǎn)即為環(huán)首的位置。

             

            6、如何判斷兩個(gè)鏈表是否交叉?如果找到交叉點(diǎn)?
                 思路同5

            posted @ 2011-09-06 17:33 IT菜鳥 閱讀(229) | 評(píng)論 (0)編輯 收藏

            精品久久久久久无码不卡| 久久综合给合久久国产免费| 日本高清无卡码一区二区久久| 人妻丰满?V无码久久不卡| 中文国产成人精品久久亚洲精品AⅤ无码精品| 久久影视国产亚洲| 麻豆精品久久久久久久99蜜桃 | 久久SE精品一区二区| 亚洲人成精品久久久久| 国产成人久久精品激情| 99久久精品久久久久久清纯| 欧美久久久久久午夜精品| 久久久久久久女国产乱让韩| 1000部精品久久久久久久久| 国产ww久久久久久久久久| 久久这里的只有是精品23| 久久亚洲AV成人无码电影| 国产成人99久久亚洲综合精品| 久久精品免费全国观看国产| 久久久久成人精品无码中文字幕 | 亚洲国产精品无码久久久蜜芽| 国产综合久久久久| 久久亚洲高清综合| 久久精品国产亚洲av麻豆色欲| 88久久精品无码一区二区毛片| 亚洲欧美久久久久9999| 99久久超碰中文字幕伊人| 久久人人爽人人爽人人片AV麻豆| 色狠狠久久AV五月综合| 国产成人无码精品久久久免费| 久久久亚洲欧洲日产国码是AV| 久久99精品国产99久久| 奇米影视7777久久精品人人爽| 7国产欧美日韩综合天堂中文久久久久 | 久久久中文字幕| 精品久久久久成人码免费动漫| 久久91精品国产91久久户| 老男人久久青草av高清| 国产999精品久久久久久| 99久久国产综合精品女同图片| 久久99精品免费一区二区|