日韩av高清在线影院,欧美日韩国产综合色视频在线,日韩精品人妻在线视频,内射极品高挑少妇人妻,久久久国产成人免费,97久久视频在线观看,人妻中文字幕日韩有码人妻熟女,亚洲国产成人精品福利,99精品国产福利在线观看

牛人寫(xiě)的設(shè)計(jì)游戲服務(wù)器 國(guó)外牛人小戶型設(shè)計(jì)

有段時(shí)間沒(méi)有研究技術(shù)了,這次正好看到了新版的mangos,較之以前我看的版本有了比較大的完善,于是再次瀏覽了下他的代碼,也借此機(jī)會(huì)整理下我在游戲服務(wù)器開(kāi)發(fā)方面的一些心得,與大家探討。
  另外由于為避免與公司引起一些不必要的糾紛,我所描述的全都是通過(guò)google能夠找到的資料,所以也可以認(rèn)為我下面的內(nèi)容都是網(wǎng)上所找資料的整理合集。在平時(shí)的開(kāi)發(fā)中我也搜索過(guò)相關(guān)的中文網(wǎng)頁(yè),很少有講游戲服務(wù)器相關(guān)技術(shù)的,大家的討論主要還是集中在3D相關(guān)技術(shù),所以也希望我將開(kāi)始的這幾篇文章能夠起到拋磚引玉的作用,潛水的兄弟們也都上來(lái)透透氣。
  要描述一項(xiàng)技術(shù)或是一個(gè)行業(yè),一般都會(huì)從其最古老的歷史開(kāi)始說(shuō)起,我本也想按著這個(gè)套路走,無(wú)奈本人乃一八零后小輩,沒(méi)有經(jīng)歷過(guò)那些苦澀的卻令人羨慕的單機(jī)游戲開(kāi)發(fā),也沒(méi)有響當(dāng)當(dāng)?shù)哪玫某鍪值膬?yōu)秀作品,所以也就只能就我所了解的一些技術(shù)做些簡(jiǎn)單的描述。一來(lái)算是敦促自己對(duì)知識(shí)做個(gè)梳理,二來(lái)與大家探討的過(guò)程也能夠找到我之前學(xué)習(xí)的不足和理解上的錯(cuò)誤,最后呢,有可能的話也跟業(yè)內(nèi)的同行們混個(gè)臉熟,哪天要是想換個(gè)工作了也好有個(gè)人幫忙介紹下。最后的理由有些俗了。
  關(guān)于游戲開(kāi)發(fā),正如云風(fēng)在其blog上所說(shuō),游戲項(xiàng)目始終只是個(gè)小工程,另外開(kāi)發(fā)時(shí)間還是個(gè)很重要的問(wèn)題,所以軟件工程的思想及方法在大部分的游戲公司中并不怎么受歡迎。當(dāng)然這也只是從我個(gè)人一些膚淺的了解所得,可能不夠充分。從游戲開(kāi)發(fā)的程序團(tuán)隊(duì)的人員構(gòu)成上也可看出來(lái),基本只能算作是小開(kāi)發(fā)團(tuán)隊(duì)。有些工作室性質(zhì)的開(kāi)發(fā)團(tuán)隊(duì),那就更簡(jiǎn)單了。
  我所了解的早些的開(kāi)發(fā)團(tuán)隊(duì),其成員間沒(méi)有什么嚴(yán)格的分工,大家憑興趣自由選擇一些模塊來(lái)負(fù)責(zé),完成了再去負(fù)責(zé)另一模塊,有其他同事的工作需要接手或協(xié)助的也會(huì)立即轉(zhuǎn)入。所以游戲開(kāi)發(fā)人員基本都是多面手,從網(wǎng)絡(luò)到數(shù)據(jù)庫(kù),從游戲邏輯到圖形圖象,每一項(xiàng)都有所了解,并能實(shí)際應(yīng)用。或者說(shuō)都具有非常強(qiáng)的學(xué)習(xí)能力,在接手一項(xiàng)新的任務(wù)后能在很短的時(shí)間內(nèi)對(duì)該領(lǐng)域的技術(shù)迅速掌握并消化,而且還能現(xiàn)炒現(xiàn)賣(mài)。當(dāng)然,這也與早期2D游戲的技術(shù)要求相對(duì)比較簡(jiǎn)單,游戲邏輯也沒(méi)有現(xiàn)在這般復(fù)雜有關(guān)。而更重要的可能是,都是被逼出來(lái)的吧!:)
  好了,閑話少說(shuō),下一篇,也就是第一篇了,主題為,服務(wù)器結(jié)構(gòu)探討。


服務(wù)器結(jié)構(gòu)探討 -- 最簡(jiǎn)單的結(jié)構(gòu)
  所謂服務(wù)器結(jié)構(gòu),也就是如何將服務(wù)器各部分合理地安排,以實(shí)現(xiàn)最初的功能需求。所以,結(jié)構(gòu)本無(wú)所謂正確與錯(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)的定義也就沒(méi)有定論。在這里,我們不打算對(duì)現(xiàn)有游戲結(jié)構(gòu)做評(píng)價(jià),而是試著從頭開(kāi)始搭建一個(gè)我們需要的MMOG結(jié)構(gòu)。
  對(duì)于一個(gè)最簡(jiǎn)單的游戲服務(wù)器來(lái)說(shuō),它只需要能夠接受來(lái)自客戶端的連接請(qǐng)求,然后處理客戶端在游戲世界中的移動(dòng)及交互,也即游戲邏輯處理即可。如果我們把這兩項(xiàng)功能集成到一個(gè)服務(wù)進(jìn)程中,則最終的結(jié)構(gòu)很簡(jiǎn)單:
  client ----- server
  嗯,太簡(jiǎn)單了點(diǎn),這樣也敢叫服務(wù)器結(jié)構(gòu)?好吧,現(xiàn)在我們來(lái)往里面稍稍加點(diǎn)東西,讓它看起來(lái)更像是服務(wù)器結(jié)構(gòu)一些。
  一般來(lái)說(shuō),我們?cè)诮尤胗螒蚍?wù)器的時(shí)候都會(huì)要提供一個(gè)帳號(hào)和密碼,驗(yàn)證通過(guò)后才能進(jìn)入。關(guān)于為什么要提供用戶名和密碼才能進(jìn)入的問(wèn)題我們這里不打算做過(guò)多討論,云風(fēng)曾對(duì)此也提出過(guò)類(lèi)似的疑問(wèn),并給出了只用一個(gè)標(biāo)識(shí)串就能進(jìn)入的設(shè)想,有興趣的可以去看看他們的討論。但不管是采用何種方式進(jìn)入,照目前看來(lái)我們的服務(wù)器起碼得提供一個(gè)帳號(hào)驗(yàn)證的功能。
  我們把觀察點(diǎn)先集中在一個(gè)大區(qū)內(nèi)。在大多數(shù)情況下,一個(gè)大區(qū)內(nèi)都會(huì)有多組游戲服,也就是多個(gè)游戲世界可供選擇。簡(jiǎn)單點(diǎn)來(lái)實(shí)現(xiàn),我們完全可以拋棄這個(gè)大區(qū)的概念,認(rèn)為一個(gè)大區(qū)也就是放在同一個(gè)機(jī)房的多臺(tái)服務(wù)器組,各服務(wù)器組間沒(méi)有什么關(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)入后開(kāi)始帳號(hào)驗(yàn)證過(guò)程,驗(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ù)器資源配置的問(wèn)題。因?yàn)榈卿浄幚淼倪壿嬒鄬?duì)來(lái)說(shuō)比較簡(jiǎn)單,就是將玩家提交的帳號(hào)和密碼送到數(shù)據(jù)庫(kù)進(jìn)行驗(yàn)證,和生成會(huì)話密鑰發(fā)送給游戲服和客戶端,操作完成后連接就會(huì)立即斷開(kāi),而且玩家在以后的游戲過(guò)程中不會(huì)再與登錄服打任何交道。這樣處理短連接的過(guò)程使得系統(tǒng)在大多數(shù)情況下都是比較空閑的,但是在某些時(shí)候,由于請(qǐng)求比較密集,比如開(kāi)新服的時(shí)候,登錄服的負(fù)載又會(huì)比較大,甚至?xí)幚聿贿^(guò)來(lái)。
  另外在實(shí)際的游戲運(yùn)營(yíng)中,有些游戲世界很火爆,而有些游戲世界卻非常冷清,甚至沒(méi)有多少人玩的情況也是很常見(jià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ì)出來(lái)游戲世界列表,之后是排隊(duì)進(jìn)入游戲世界,開(kāi)始游戲...
  可以看到跟前面的描述有個(gè)很明顯的不同,那就是要先驗(yàn)證帳號(hào)再選擇游戲世界。這種結(jié)構(gòu)也就使得登錄服不是固定配備給個(gè)游戲世界,而是全區(qū)共有的。
  我們可以試著從實(shí)際需求的角度來(lái)考慮一下這個(gè)問(wèn)題。正如我們之前所描述過(guò)的那樣,登錄服在大多數(shù)情況下都是比較空閑的,也許我們的一個(gè)擁有20個(gè)游戲世界的大區(qū)僅僅使用10臺(tái)或更少的登錄服即可滿足需求。而當(dāng)在開(kāi)新區(qū)的時(shí)候,或許要配備40臺(tái)登錄服才能應(yīng)付那如潮水般涌入的玩家登錄請(qǐng)求。所以,登錄服在設(shè)計(jì)上應(yīng)該能滿足這種動(dòng)態(tài)增刪的需求,我們可以在任何時(shí)候?yàn)榇髤^(qū)增加或減少登錄服的部署。
  當(dāng)然,在這里也不會(huì)存在要求添加太多登錄服的情況。還是拿開(kāi)新區(qū)的情況來(lái)說(shuō),即使新增加登錄服滿足了玩家登錄的請(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ù)持久化的問(wèn)題也在這里考慮一下。一般來(lái)說(shuō),使用現(xiàn)有的商業(yè)數(shù)據(jù)庫(kù)系統(tǒng)比自己手工技術(shù)先進(jìn)要明智得多。我們需要持久化的數(shù)據(jù)有玩家的帳號(hào)及密碼,玩家創(chuàng)建的角色相關(guān)信息,另外還有一些游戲世界全局共有數(shù)據(jù)也需要持久化。
  好了,需求已經(jīng)提出來(lái)了,現(xiàn)在來(lái)考慮如何將其實(shí)現(xiàn)。
  對(duì)于負(fù)載均衡來(lái)說(shuō),已有了成熟的解決方案。一般最常用,也最簡(jiǎn)單部署的應(yīng)該是基于DNS的負(fù)載均衡系統(tǒng)了,其通過(guò)在DNS中為一個(gè)域名配置多個(gè)IP地址來(lái)實(shí)現(xiàn)。最新的DNS服務(wù)已實(shí)現(xiàn)了根據(jù)服務(wù)器系統(tǒng)狀態(tài)來(lái)實(shí)現(xiàn)的動(dòng)態(tài)負(fù)載均衡,也就是實(shí)現(xiàn)了真正意義上的負(fù)載均衡,這樣也就有效地解決了當(dāng)某臺(tái)登錄服當(dāng)機(jī)后,DNS服務(wù)器不能立即做出反應(yīng)的問(wèn)題。當(dāng)然,如果找不到這樣的解決方案,自己從頭打造一個(gè)也并不難。而且,通過(guò)DNS來(lái)實(shí)現(xiàn)的負(fù)載均衡已經(jīng)包含了所做的修改對(duì)登錄服及客戶端的透明。
  而對(duì)于數(shù)據(jù)庫(kù)的應(yīng)用,在這種結(jié)構(gòu)下,登錄服及游戲世界服都會(huì)需要連接數(shù)據(jù)庫(kù)。從數(shù)據(jù)庫(kù)服務(wù)器的部署上來(lái)說(shuō),可以將帳號(hào)和角色數(shù)據(jù)都放在一個(gè)中心數(shù)據(jù)庫(kù)中,也可分為兩個(gè)不同的庫(kù)分別來(lái)處理,基到從物理上分到兩臺(tái)不同的服務(wù)器上去也行。
  但是對(duì)于不同的游戲世界來(lái)說(shuō),其角色及游戲內(nèi)數(shù)據(jù)都是互相獨(dú)立的,所以一般情況下也就為每個(gè)游戲世界單獨(dú)配備一臺(tái)數(shù)據(jù)庫(kù)服務(wù)器,以減輕數(shù)據(jù)庫(kù)的壓力。所以,整體的服務(wù)器結(jié)構(gòu)應(yīng)該是一個(gè)大區(qū)有一臺(tái)帳號(hào)數(shù)據(jù)庫(kù)服務(wù)器,所有的登錄服都連接到這里。而每個(gè)游戲世界都有自己的游戲數(shù)據(jù)庫(kù)服務(wù)器,只允許本游戲世界內(nèi)的服務(wù)器連接。
  最后,我們的服務(wù)器結(jié)構(gòu)就像這樣:
             大區(qū)服務(wù)器          /   |       / |       登錄服1 登錄服2 世界服1 世界服2            |   |   |            |   | |          帳號(hào)數(shù)據(jù)庫(kù) DBS DBS
  這里既然討論到了大區(qū)及帳號(hào)數(shù)據(jù)庫(kù),所以順帶也說(shuō)一下關(guān)于激活大區(qū)的概念。wow中一共有八個(gè)大區(qū),我們想要進(jìn)入某個(gè)大區(qū)游戲之前,必須到官網(wǎng)上激活這個(gè)區(qū),這是為什么呢?
  一般來(lái)說(shuō),在各個(gè)大區(qū)帳號(hào)數(shù)據(jù)庫(kù)之上還有一個(gè)總的帳號(hào)數(shù)據(jù)庫(kù),我們可以稱(chēng)它為中心數(shù)據(jù)庫(kù)。比如我們?cè)诠倬W(wǎng)上注冊(cè)了一個(gè)帳號(hào),這時(shí)帳號(hào)數(shù)據(jù)是只保存在中心數(shù)據(jù)庫(kù)上的。而當(dāng)我們要到一區(qū)去創(chuàng)建角色開(kāi)始游戲的時(shí)候,在一區(qū)的帳號(hào)數(shù)據(jù)庫(kù)中并沒(méi)有我們的帳號(hào)數(shù)據(jù),所以,我們必須先到官網(wǎng)上做一次激活操作。這個(gè)激活的過(guò)程也就是從中心庫(kù)上把我們的帳號(hào)數(shù)據(jù)拷貝到所要到的大區(qū)帳號(hào)數(shù)據(jù)庫(kù)中。
Re:游戲服務(wù)器技術(shù)交流
打算寫(xiě)一個(gè)系列,也算給自己一個(gè)交代,但不知道能堅(jiān)持多久
內(nèi)容計(jì)劃的比較多,已經(jīng)打了一些草稿,還要慢慢整理,從服務(wù)器結(jié)構(gòu)到?jīng)]個(gè)獨(dú)立服務(wù)器內(nèi)部的模塊劃分,及大的框架代碼實(shí)現(xiàn)都有所涉及
另外技術(shù)人員的文章大都比較中規(guī)中矩,我想嘗試一下比較輕松的寫(xiě)法,不知道會(huì)不會(huì)讓人覺(jué)得有些做作或是有賣(mài)弄之嫌
白天上班,只能晚上回去整理,所以會(huì)比較慢
Re:游戲服務(wù)器技術(shù)交流
小弟我也是80后,目前還沒(méi)有入行,也來(lái)拋個(gè)磚頭~ ^_^
關(guān)于服務(wù)器的安排。我覺(jué)得按照樓主所描述的安排,是把一定的任務(wù)安排給指定的服務(wù)器,而且這種安排是固定的(運(yùn)行期間無(wú)法更改)。那么是否能把這種安排變?yōu)閯?dòng)態(tài)的?也就是說(shuō)有這么一組連在局域網(wǎng)里的服務(wù)器,有一臺(tái)服務(wù)器作為玩家登錄游戲的入口,這個(gè)安排是固定的,但其他服務(wù)器的任務(wù)是根據(jù)負(fù)荷動(dòng)態(tài)分配的。假如把各個(gè)不同的模塊做成進(jìn)程,無(wú)論是帳號(hào)驗(yàn)證、行走同步、技能邏輯處理還是別的什么,凡是負(fù)荷沒(méi)有很大關(guān)聯(lián)的模塊都做成單獨(dú)的進(jìn)程,然后由一臺(tái)特定的服務(wù)器進(jìn)行各個(gè)模塊進(jìn)程和服務(wù)器的負(fù)載監(jiān)測(cè),把大負(fù)荷的模塊進(jìn)程遷移到小負(fù)荷的物理服務(wù)器上去。這樣也許會(huì)有更合適的服務(wù)器安排,而且通過(guò)增加服務(wù)器就可以提高負(fù)載能力。
Re: 游戲服務(wù)器技術(shù)交流
不錯(cuò),才剛開(kāi)了個(gè)頭就飄小紅旗了
那個(gè)把所有功能組件全部進(jìn)程化,而且全部動(dòng)態(tài)配置的想法太前衛(wèi)了
服務(wù)器設(shè)計(jì)不光要考慮靈活性,更要考慮可靠性,穩(wěn)定性,設(shè)計(jì)盡可能得簡(jiǎn)潔,只有在簡(jiǎn)單的設(shè)計(jì)無(wú)法滿足需求的時(shí)候才會(huì)考慮復(fù)雜的實(shí)現(xiàn)
服務(wù)器結(jié)構(gòu)探討 -- 簡(jiǎn)單的世界服實(shí)現(xiàn)
  討論了這么久我們一直都還沒(méi)有進(jìn)入游戲世界服務(wù)器內(nèi)部,現(xiàn)在就讓我們來(lái)窺探一下里面的結(jié)構(gòu)吧。
  對(duì)于現(xiàn)在大多數(shù)MMORPG來(lái)說(shuō),游戲服務(wù)器要處理的基本邏輯有移動(dòng)、聊天、技能、物品、任務(wù)和生物等,另外還有地圖管理與消息廣播來(lái)對(duì)其他高級(jí)功能做支撐。如縱隊(duì)、好友、公會(huì)、戰(zhàn)場(chǎng)和副本等,這些都是通過(guò)基本邏輯功能組合或擴(kuò)展而成。
  在所有這些基礎(chǔ)邏輯中,與我們要討論的服務(wù)器結(jié)構(gòu)關(guān)系最緊密的當(dāng)屬地圖管理方式。決定了地圖的管理方式也就決定了我們的服務(wù)器結(jié)構(gòu),我們?nèi)匀幌葟淖詈?jiǎn)單的實(shí)現(xiàn)方式開(kāi)始說(shuō)起。
  回想一下我們?cè)鴳?zhàn)斗過(guò)無(wú)數(shù)個(gè)夜晚的暗黑破壞神,整個(gè)暗黑的世界被分為了若干個(gè)獨(dú)立的小地圖,當(dāng)我們?cè)诘貓D間穿越時(shí),一般都要經(jīng)過(guò)一個(gè)叫做傳送門(mén)的裝置。世界中有些地圖間雖然在地理上是直接相連的,但我們發(fā)現(xiàn)其游戲內(nèi)部的邏輯卻是完全隔離的??梢赃@樣認(rèn)為,一塊地圖就是一個(gè)獨(dú)立的數(shù)據(jù)處理單元。
  既然如此,我們就把每塊地圖都當(dāng)作是一****立的服務(wù)器,他提供了在這塊地圖上游戲時(shí)的所有邏輯功能,至于內(nèi)部結(jié)構(gòu)如何劃分我們暫不理會(huì),先把他當(dāng)作一個(gè)黑盒子吧。
  當(dāng)兩個(gè)人合作做一件事時(shí),我們可以以對(duì)等的關(guān)系相互協(xié)商著來(lái)做,而且一般也都不會(huì)有什么問(wèn)題。當(dāng)人數(shù)增加到三個(gè)時(shí),我們對(duì)等的合作關(guān)系可能會(huì)有些復(fù)雜,因?yàn)槲覀兠總€(gè)人都同時(shí)要與另兩個(gè)人合作協(xié)商。正如俗語(yǔ)所說(shuō)的那樣,三個(gè)和尚可能會(huì)碰到?jīng)]水喝的情況。當(dāng)人數(shù)繼續(xù)增加,情況就變得不那么簡(jiǎn)單了,我們得需要一個(gè)管理者來(lái)對(duì)我們的工作進(jìn)行分工、協(xié)調(diào)。游戲的地圖服務(wù)器之間也是這么回事。
  一般來(lái)說(shuō),我們的游戲世界不可能會(huì)只有一塊或者兩塊小地圖,那順理成章的,也就需要一個(gè)地圖管理者。先稱(chēng)它為游戲世界的中心服務(wù)器吧,畢竟是管理者嘛,大家都以它為中心。
  中心服務(wù)器主要維護(hù)一張地圖ID到地圖服務(wù)器地址的映射表。當(dāng)我們要進(jìn)入某張地圖時(shí),會(huì)從中心服上取得該地圖的IP和port告訴客戶端,客戶端主動(dòng)去連接,這樣進(jìn)入他想要去的游戲地圖。在整個(gè)游戲過(guò)程中,客戶端始終只會(huì)與一臺(tái)地圖服務(wù)器保持連接,當(dāng)要切換地圖的時(shí)候,在獲取到新地圖的地址后,會(huì)先與當(dāng)前地圖斷開(kāi)連接,再進(jìn)入新的地圖,這樣保證玩家數(shù)據(jù)在服務(wù)器上只有一份。
  我們來(lái)看看結(jié)構(gòu)圖是怎樣的:
    中心服務(wù)器//登錄服 地圖1 地圖2 地圖n| / /| / /    客戶端
  很簡(jiǎn)單,不是嗎。但是簡(jiǎn)單并不表示功能上會(huì)有什么損失,簡(jiǎn)單也更不能表示游戲不能賺錢(qián)。早期不少游戲也確實(shí)采用的就是這種簡(jiǎn)單結(jié)構(gòu)。
Re:游戲服務(wù)器技術(shù)交流
我有個(gè)問(wèn)題,客戶端在整個(gè)游戲過(guò)程中,網(wǎng)絡(luò)連接不是持續(xù)的,而是要有很多斷開(kāi)再重連的過(guò)程,在這個(gè)過(guò)程中如何保證安全?顯然不能每次都重新輸入用戶名和密碼;如果是客戶端自動(dòng)把這些信息在重連時(shí)發(fā)出,那么用戶名和密碼就需要長(zhǎng)期留在客戶端的內(nèi)存里,那么會(huì)給****木馬提供便利;如果是客戶端把一個(gè)短期有效的識(shí)別數(shù)據(jù)發(fā)給服務(wù)器來(lái)做用戶驗(yàn)證,從第二次傳輸開(kāi)始就有被他人截獲的可能,而一旦被截獲,那么別人就可能搶在合法用戶之前就切換服務(wù)器,從而導(dǎo)致用戶游戲財(cái)富的流失或者用戶被拒絕服務(wù)。所以我想,是否有一種辦法,能夠避免重新連接,也就是說(shuō)需要的時(shí)候能夠把一個(gè)網(wǎng)絡(luò)連接重定向到另一個(gè)服務(wù)器,但是這個(gè)過(guò)程僅僅發(fā)生在服務(wù)器組的局域網(wǎng)內(nèi),這個(gè)過(guò)程是安全的,而對(duì)于客戶端來(lái)說(shuō)則是透明的過(guò)程。如果要避免斷開(kāi)重連,還有個(gè)辦法就是用戶始終只和一臺(tái)特定的服務(wù)器保持網(wǎng)絡(luò)連接,由這臺(tái)服務(wù)器來(lái)轉(zhuǎn)發(fā)客戶端與其他服務(wù)器之間的數(shù)據(jù)流,但是這樣的話那臺(tái)特定的服務(wù)器的符合就很大了,除非讓其他的邏輯服務(wù)器一起來(lái)客串入口服務(wù)器,只是不知道這樣會(huì)有什么影響。該怎么處理這樣的問(wèn)題呢?
Re:游戲服務(wù)器技術(shù)交流
樓上的很對(duì),容我慢慢來(lái)說(shuō)嘛,呵呵
這個(gè)結(jié)構(gòu)是早期的結(jié)構(gòu),現(xiàn)在都不會(huì)采用這種每次都要斷開(kāi)再重連的方式了
不過(guò)這種方式一樣可以做的很安全,每次連接時(shí)生成一個(gè)有效時(shí)間很短的臨時(shí)密鑰就行了
至于你說(shuō)怕被別人截獲,所有的連接都是可以被截獲的,問(wèn)題只在于那個(gè)門(mén)檻有多高
服務(wù)器結(jié)構(gòu)探討 -- 繼續(xù)世界服
  都已經(jīng)看出來(lái)了,這種每切換一次地圖就要重新連接服務(wù)器的方式實(shí)在是不夠優(yōu)雅,而且在實(shí)際游戲運(yùn)營(yíng)中也發(fā)現(xiàn),地圖切換導(dǎo)致的卡號(hào),復(fù)制裝備等問(wèn)題非常多,這里完全就是一個(gè)事故多發(fā)地段,如何避免這種頻繁的連接操作呢?
  最直接的方法就是把那個(gè)圖倒轉(zhuǎn)過(guò)來(lái)就行了??蛻舳酥恍枰B接到中心服上,所有到地圖服務(wù)器的數(shù)據(jù)都由中心服來(lái)轉(zhuǎn)發(fā)。很完美的解決方案,不是嗎?
  這種結(jié)構(gòu)在實(shí)際的部署中也遇到了一些挑戰(zhàn)。對(duì)于一般的MMORPG服務(wù)器來(lái)說(shuō),單臺(tái)服務(wù)器的承載量平均在2000左右,如果你的服務(wù)器很不幸地只能帶1000人,沒(méi)關(guān)系,不少游戲都是如此;如果你的服務(wù)器上跑了3000多玩家依然比較流暢,那你可以自豪地告訴你的策劃,多設(shè)計(jì)些大量消耗服務(wù)器資源的玩法吧,比如大型國(guó)戰(zhàn)、公會(huì)戰(zhàn)爭(zhēng)等。
  2000人,似乎我們的策劃朋友們不大愿意接受這個(gè)數(shù)字。我們將地圖服務(wù)器分開(kāi)來(lái)原來(lái)也是想將負(fù)載分開(kāi),以多帶些客戶端,現(xiàn)在要所有的連接都從中心服上轉(zhuǎn)發(fā),那連接數(shù)又遇到單臺(tái)服務(wù)器的可最大承載量的瓶頸了。
  這里有必要再解釋下這個(gè)數(shù)字。我知道,有人一定會(huì)說(shuō),才帶2000人,那是你水平不行,我隨便寫(xiě)個(gè)TCP服務(wù)器都可帶個(gè)五六千連接。問(wèn)題恰恰在于你是隨便寫(xiě)的,而MMORPG的服務(wù)器是復(fù)雜設(shè)計(jì)的。如果一個(gè)演示socketAPI用的echo服務(wù)器就能滿足MMOG服務(wù)器的需求,那寫(xiě)服務(wù)器該是件多么愜意的事啊。
  但我們所遇到的事實(shí)是,服務(wù)器收到一個(gè)移動(dòng)包后,要向周?chē)腥藦V播,而不是echo服務(wù)器那樣簡(jiǎn)單的回應(yīng);服務(wù)器在收到一個(gè)連接斷開(kāi)通知時(shí)要向很多人通知玩家退出事件,并將該玩家的資料寫(xiě)入數(shù)據(jù)庫(kù),而不是echo服務(wù)器那樣什么都不需要做;服務(wù)器在收到一個(gè)物品使用請(qǐng)求包后要做一系列的邏輯判斷以檢查玩家有沒(méi)有作弊;服務(wù)器上還啟動(dòng)著很多定時(shí)器用來(lái)更新游戲世界的各種狀態(tài)......
  其實(shí)這么一比較,我們也看出資源消耗的所在了:服務(wù)器上大量的復(fù)雜的邏輯處理。再回過(guò)頭來(lái)看看我們想要實(shí)現(xiàn)的結(jié)構(gòu),我們既想要有一個(gè)唯一的入口,使得客戶端不用頻繁改變連接,又希望這個(gè)唯一入口的負(fù)載不會(huì)太大,以致于接受不了多少連接。
  仔細(xì)看一看這個(gè)需求,我們想要的僅僅只是一臺(tái)管理連接的服務(wù)器,并不打算讓他承擔(dān)太多的游戲邏輯。既然如此,那五六千個(gè)連接也還有滿足我們的要求。至少在現(xiàn)在來(lái)說(shuō),一個(gè)游戲世界內(nèi),也就是一組服務(wù)器內(nèi)同時(shí)有五六千個(gè)在線的玩家還是件讓人很興奮的事。事實(shí)上,在大多數(shù)游戲的大部分時(shí)間里,這個(gè)數(shù)字也是很讓人眼紅的。
  什么?你說(shuō)夢(mèng)幻、魔獸還有史先生的那個(gè)什么****遠(yuǎn)不止這么點(diǎn)人了!噢,我說(shuō)的是大多數(shù),是大多數(shù),不包括那些明星。你知道大陸現(xiàn)在有多少游戲在運(yùn)營(yíng)嗎?或許你又該說(shuō),我們不該在一開(kāi)始就把自己的目標(biāo)定的太低!好吧,我們還是先不談這個(gè)。
  繼續(xù)我們的結(jié)構(gòu)討論。一般來(lái)說(shuō),我們把這臺(tái)負(fù)責(zé)連接管理的服務(wù)器稱(chēng)為網(wǎng)關(guān)服務(wù)器,因?yàn)閮?nèi)部的數(shù)據(jù)都要通過(guò)這個(gè)網(wǎng)關(guān)才能出去,不過(guò)從這臺(tái)服務(wù)器提供的功能來(lái)看,稱(chēng)其為反向代理服務(wù)器可能更合適。我們也不在這個(gè)名字上糾纏了,就按大家通用的叫法,還是稱(chēng)他為網(wǎng)關(guān)服務(wù)器吧。
  網(wǎng)關(guān)之后的結(jié)構(gòu)我們依然可以采用之前描述的方案,只是,似乎并沒(méi)有必要為每一個(gè)地圖都開(kāi)一個(gè)獨(dú)立的監(jiān)聽(tīng)端口了。我們可以試著對(duì)地圖進(jìn)行一些劃分,由一個(gè)Master Server來(lái)管理一些更小的Zone Server,玩家通過(guò)網(wǎng)關(guān)連接到MasterServer上,而實(shí)際與地圖有關(guān)的邏輯是分派給更小的Zone Server去處理。
  最后的結(jié)構(gòu)看起來(lái)大概是這樣的:
Zone Server Zone Server//Master Server Master Server/ // /Gateway Server /| /| /| Center Server||Client

Re: Re: 游戲服務(wù)器技術(shù)交流


bigbook2000: Re: 游戲服務(wù)器技術(shù)交流
什么MMORPG的邏輯可以使單臺(tái)服務(wù)器能上2000?
NPC都是死的?玩家都不干活?
終于有了一個(gè)反對(duì)的聲音


首先2000這個(gè)數(shù)字是我統(tǒng)計(jì)的一個(gè)平均值,統(tǒng)計(jì)的依據(jù)來(lái)自于與其他人的討論和別人提供的數(shù)據(jù),另外一些公司提供的運(yùn)營(yíng)數(shù)據(jù)打點(diǎn)折也可以估算個(gè)大概?;蛟S是大家都夸大了自己的能力,或公司公開(kāi)的數(shù)據(jù)水分超過(guò)了我的估計(jì)?呵呵
當(dāng)然,我們的游戲也沒(méi)有單臺(tái)2000,但我認(rèn)為現(xiàn)在的服務(wù)器存在很大的提升余地
至于你說(shuō)的NPC是死的,玩家干不干活
NPC最消耗系統(tǒng)資源的當(dāng)屬AI了,特別是一些復(fù)雜的尋路,這個(gè)完全可以分離到一臺(tái)單獨(dú)的AI服務(wù)器上,不少游戲都是這么做的,從一些泄漏出來(lái)的服務(wù)器端上也可以看到
生物管理,狀態(tài)更新和消息廣播在Zone Server上做,其他公共邏輯模塊在Master Server和CenterServer上跑,那這樣其實(shí)也就沒(méi)有一個(gè)單臺(tái)服務(wù)器承載量的概念了,可能要說(shuō)數(shù)據(jù)的話還是以一組服務(wù)器為單位比較合適
另外我一直以wow的結(jié)構(gòu)來(lái)做參考,希望實(shí)現(xiàn)的也跟wow差不多,所以這些數(shù)字也可以算做是我的目標(biāo)吧
服務(wù)器結(jié)構(gòu)探討 -- 最終的結(jié)構(gòu)
  如果我們就此打住,可能馬上就會(huì)有人要嗤之以鼻了,就這點(diǎn)古董級(jí)的技術(shù)也敢出來(lái)現(xiàn)。好吧,我們還是把之前留下的問(wèn)題拿出來(lái)解決掉吧。
  一般來(lái)說(shuō),當(dāng)某一部分能力達(dá)不到我們的要求時(shí),最簡(jiǎn)單的解決方法就是在此多投入一點(diǎn)資源。既然想要更多的連接數(shù),那就再加一臺(tái)網(wǎng)關(guān)服務(wù)器吧。新增加了網(wǎng)關(guān)服后需要在大區(qū)服上做相應(yīng)的支持,或者再簡(jiǎn)單點(diǎn),有一臺(tái)主要的網(wǎng)關(guān)服,當(dāng)其負(fù)載較高時(shí),主動(dòng)將新到達(dá)的連接重定向到其他網(wǎng)關(guān)服上。
  而對(duì)于游戲服來(lái)說(shuō),有一臺(tái)還是多臺(tái)網(wǎng)關(guān)服是沒(méi)有什么區(qū)別的。每個(gè)代表客戶端玩家的對(duì)象內(nèi)部都保留一個(gè)代表其連接的對(duì)象,消息廣播時(shí)要求每個(gè)玩家對(duì)象使用自己的連接對(duì)象發(fā)送數(shù)據(jù)即可,至于連接是在什么地方,那是完全透明的。當(dāng)然,這只是一種簡(jiǎn)單的實(shí)現(xiàn),也是普通使用的一種方案,如果后期想對(duì)消息廣播做一些優(yōu)化的話,那可能才需要多考慮一下。
  既然說(shuō)到了優(yōu)化,我們也稍稍考慮一下現(xiàn)在結(jié)構(gòu)下可能采用的優(yōu)化方案。
  首先是當(dāng)前的ZoneServer要做的事情太多了,以至于他都處理不了多少連接。這其中最消耗系統(tǒng)資源的當(dāng)屬生物的AI處理了,尤其是那些復(fù)雜的尋路算法,所以我們可以考慮把這部分AI邏輯獨(dú)立出來(lái),由一臺(tái)單獨(dú)的AI服務(wù)器來(lái)承擔(dān)。
  然后,我們可以試著把一些與地圖數(shù)據(jù)無(wú)關(guān)的公共邏輯放到Master Server上去實(shí)現(xiàn),這樣ZoneServer上只保留了與地圖數(shù)據(jù)緊密相關(guān)的邏輯,如生物管理,玩家移動(dòng)和狀態(tài)更新等。
  還有聊天處理邏輯,這部分與游戲邏輯沒(méi)有任何關(guān)聯(lián),我們也完全可以將其獨(dú)立出來(lái),放到一臺(tái)單獨(dú)的聊天服務(wù)器上去實(shí)現(xiàn)。
  最后是數(shù)據(jù)庫(kù)了,為了減輕數(shù)據(jù)庫(kù)的壓力,提高數(shù)據(jù)請(qǐng)求的響應(yīng)速度,我們可以在數(shù)據(jù)庫(kù)之前建立一個(gè)數(shù)據(jù)庫(kù)緩存服務(wù)器,將一些常用數(shù)據(jù)緩存在此,服務(wù)器與數(shù)據(jù)庫(kù)的通信都要通過(guò)這臺(tái)服務(wù)器進(jìn)行代理。緩存的數(shù)據(jù)會(huì)定時(shí)的寫(xiě)入到后臺(tái)數(shù)據(jù)庫(kù)中。
  好了,做完這些優(yōu)化我們的服務(wù)器結(jié)構(gòu)大體也就定的差不多了,暫且也不再繼續(xù)深入,更細(xì)化的內(nèi)容等到各個(gè)部分實(shí)現(xiàn)的時(shí)候再探討。
  好比我們?nèi)タ匆粓?chǎng)晚會(huì),舞臺(tái)上演員們按著預(yù)定的節(jié)目單有序地上演著,但這就是整場(chǎng)晚會(huì)的全部嗎?顯然不止,在幕后還有太多太多的人在忙碌著,甚至在晚會(huì)前和晚會(huì)后都有。我們的游戲服務(wù)器也如此。
  在之前描述的部分就如同舞臺(tái)上的演員,是我們能直接看到的,幕后的工作人員我們也來(lái)認(rèn)識(shí)一下。
  現(xiàn)實(shí)中有警察來(lái)維護(hù)秩序,游戲中也如此,這就是我們常說(shuō)的GM。GM可以采用跟普通玩家一樣的拉入方式來(lái)進(jìn)入游戲,當(dāng)然權(quán)限會(huì)比普通玩家高一些,也可以提供一臺(tái)GM服務(wù)器專(zhuān)門(mén)用來(lái)處理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ī)器信息到游戲過(guò)程中的每一項(xiàng)操作都可以作為日志記錄下來(lái),以備查錯(cuò)及數(shù)據(jù)挖掘用。至于搜集玩家機(jī)器資料所涉及到的法律問(wèn)題不是我們?cè)摽紤]的。
  差不多就這么多了吧,接下來(lái)我們會(huì)按照這個(gè)大致的結(jié)構(gòu)來(lái)詳細(xì)討論各部分的實(shí)現(xiàn)。
服務(wù)器結(jié)構(gòu)探討 -- 一點(diǎn)雜談
  再?gòu)?qiáng)調(diào)一下,服務(wù)器結(jié)構(gòu)本無(wú)所謂好壞,只有是否適合自己。我們?cè)谇懊嫣接懥艘恍┰诂F(xiàn)在的游戲中見(jiàn)到過(guò)的結(jié)構(gòu),并盡我所知地分析了各自存在的一些問(wèn)題和可以做的一些改進(jìn),希望其中沒(méi)有謬誤,如果能給大家也帶來(lái)些啟發(fā)那自然更好。
  突然發(fā)現(xiàn)自己一旦羅嗦起來(lái)還真是沒(méi)完沒(méi)了。接下來(lái)先說(shuō)說(shuō)我在開(kāi)發(fā)中遇到過(guò)的一些困惑和一基礎(chǔ)問(wèn)題探討吧,這些問(wèn)題可能有人與我一樣,也曾遇到過(guò),或者正在被困擾中,而所要探討的這些基礎(chǔ)問(wèn)題向來(lái)也是爭(zhēng)論比較多的,我們也不評(píng)價(jià)其中的好與壞,只做簡(jiǎn)單的描述。
  首先是服務(wù)器操作系統(tǒng),linux與windows之爭(zhēng)隨處可見(jiàn),其實(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ò)庫(kù)在國(guó)內(nèi)的使用好像沒(méi)有見(jiàn)到,不符合中國(guó)國(guó)情嘛。:)
  然后是網(wǎng)絡(luò)協(xié)議的選擇,以前的選擇大多傾向于UDP,為了可靠傳輸一般自己都會(huì)在上面實(shí)現(xiàn)一層封裝,而現(xiàn)在更普通的是直接采用本身就很可靠的TCP,或者TCP與UDP的混用。早期選擇UDP的主要原因還是帶寬限制,現(xiàn)在寬帶普通的情況下TCP比UDP多出來(lái)的一點(diǎn)點(diǎn)開(kāi)銷(xiāo)與開(kāi)發(fā)的便利性相比已經(jīng)不算什么了。當(dāng)然,如果已有了成熟的可靠UDP庫(kù),那也可以繼續(xù)使用著。
  還有消息包格式的定義,這個(gè)曾在云風(fēng)的blog上展開(kāi)過(guò)激烈的爭(zhēng)論。消息包格式定義包括三段,包長(zhǎng)、消息碼和包體,爭(zhēng)論的焦點(diǎn)在于應(yīng)該是消息碼在前還是包長(zhǎng)在前,我們也把這個(gè)當(dāng)作是信仰問(wèn)題吧,有興趣的去云風(fēng)的blog上看看,論論。
  另外早期有些游戲的包格式定義是以特殊字符作分隔的,這樣一個(gè)好處是其中某個(gè)包出現(xiàn)錯(cuò)誤后我們的游戲還能繼續(xù)。但實(shí)際上,我覺(jué)得這是完全沒(méi)有必要的,真要出現(xiàn)這樣的錯(cuò)誤,直接斷開(kāi)這個(gè)客戶端的連接可能更安全。而且,以特殊字符做分隔的消息包定義還加大了一點(diǎn)點(diǎn)網(wǎng)絡(luò)數(shù)據(jù)量。
  最后是一個(gè)純技術(shù)問(wèn)題,有關(guān)socket連接數(shù)的最大限制。開(kāi)始學(xué)習(xí)網(wǎng)絡(luò)編程的時(shí)候我犯過(guò)這樣的錯(cuò)誤,以為port的定義為unsignedshort,所以想當(dāng)然的認(rèn)為服務(wù)器的最大連接數(shù)為65535,這會(huì)是一個(gè)硬性的限制。而實(shí)際上,一個(gè)socket描述符在windows上的定義是unsignedint,因此要有限制那也是四十多億,放心好了。
  在服務(wù)器上port是監(jiān)聽(tīng)用的,想象這樣一種情況,webserver在80端口上監(jiān)聽(tīng),當(dāng)一個(gè)連接到來(lái)時(shí),系統(tǒng)會(huì)為這個(gè)連接分配一個(gè)socket句柄,同時(shí)與其在80端口上進(jìn)行通訊;當(dāng)另一個(gè)連接到來(lái)時(shí),服務(wù)器仍然在80端口與之通信,只是分配的socket句柄不一樣。這個(gè)socket句柄才是描述每個(gè)連接的唯一標(biāo)識(shí)。按windows網(wǎng)絡(luò)編程第二版上的說(shuō)法,這個(gè)上限值配置影響。
  好了,廢話說(shuō)完了,下一篇,我們開(kāi)始進(jìn)入登錄服的設(shè)計(jì)吧。
登錄服的設(shè)計(jì) -- 功能需求
  正如我們?cè)谇懊嬖懻撨^(guò)的,登錄服要實(shí)現(xiàn)的功能相當(dāng)簡(jiǎn)單,就是帳號(hào)驗(yàn)證。為了便于描述,我們暫不引入那些討論過(guò)的優(yōu)化手段,先以最簡(jiǎn)單的方式實(shí)現(xiàn),另外也將基本以mangos的代碼作為參考來(lái)進(jìn)行描述。
  想象一下帳號(hào)驗(yàn)證的實(shí)現(xiàn)方法,最容易的那就是把用戶輸入的明文用帳號(hào)和密碼直接發(fā)給登錄服,服務(wù)器根據(jù)帳號(hào)從數(shù)據(jù)庫(kù)中取出密碼,與用戶輸入的密碼相比較。
  這個(gè)方法存在的安全隱患實(shí)在太大,明文的密碼傳輸太容易被截獲了。那我們?cè)囍趥鬏斨跋燃右幌旅?,為了服?wù)器能進(jìn)行密碼比較,我們應(yīng)該采用一個(gè)可逆的加密算法,在服務(wù)器端把這個(gè)加密后的字串還原為原始的明文密碼,然后與數(shù)據(jù)庫(kù)密碼進(jìn)行比較。既然是一個(gè)可逆的過(guò)程,那外掛****者總有辦法知道我們的加密過(guò)程,所以,這個(gè)方法仍不夠安全。
  哦,如果我們只是希望密碼不可能被還原出來(lái),那還不容易嗎,使用一個(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)游戲!如果我們總是用一種固定的算法來(lái)對(duì)密碼做散列,那外掛只需要記住這個(gè)散列后的字串就行了,用這個(gè)做密碼就可以成功登錄。
  嗯,這個(gè)問(wèn)題好解決,我們不要用固定的算法進(jìn)行散列就是了。只是,問(wèn)題在于服務(wù)器與客戶端采用的散列算法得出的字串必須是相同的,或者是可驗(yàn)證其是否匹配的。很幸運(yùn)的是,偉大的數(shù)學(xué)字們?cè)缇蜑槲覀儨?zhǔn)備好了很多優(yōu)秀的這類(lèi)算法,而且經(jīng)理論和實(shí)踐都證明他們也確實(shí)是足夠安全的。
  這其中之一是一個(gè)叫做SRP的算法,全稱(chēng)叫做Secure RemotePassword,即安全遠(yuǎn)程密碼。wow使用的是第6版,也就是SRP6算法。有關(guān)其中的數(shù)學(xué)證明,如果有人能向我解釋清楚,并能讓我真正弄明白的話,我將非常感激。不過(guò)其代碼實(shí)現(xiàn)步驟倒是并不復(fù)雜,mangos中的代碼也還算清晰,我們也不再贅述。
  登錄服除了帳號(hào)驗(yàn)證外還得提供另一項(xiàng)功能,就是在玩家的帳號(hào)驗(yàn)證成功后返回給他一個(gè)服務(wù)器列表讓他去選擇。這個(gè)列表的狀態(tài)要定時(shí)刷新,可能有新的游戲世界開(kāi)放了,也可能有些游戲世界非常不幸地停止運(yùn)轉(zhuǎn)了,這些狀態(tài)的變化都要盡可能及時(shí)地讓玩家知道。不管發(fā)生了什么事,用戶都有權(quán)利知道,特別是對(duì)于付過(guò)費(fèi)的用戶來(lái)說(shuō),我們不該藏著掖著,不是嗎?
  這個(gè)游戲世界列表的功能將由大區(qū)服來(lái)提供,具體的結(jié)構(gòu)我們?cè)谥耙裁枋鲞^(guò),這里暫不做討論。登錄服將從大區(qū)服上獲取到的游戲世界列表發(fā)給已驗(yàn)證通過(guò)的客戶端即可。好了,登錄服要實(shí)現(xiàn)的功能就這些,很簡(jiǎn)單,是吧。
  確實(shí)是太簡(jiǎn)單了,不過(guò)簡(jiǎn)單的結(jié)構(gòu)正好更適合我們來(lái)看一看游戲服務(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ù)開(kāi)始,而當(dāng)開(kāi)始一項(xiàng)新的工程時(shí),第一個(gè)寫(xiě)下的函數(shù)大多也是main。那我們就先來(lái)看看,游戲服務(wù)器代碼實(shí)現(xiàn)中,main函數(shù)都做了些什么。
  由于我在讀技術(shù)文章時(shí)最不喜看到的就是大段大段的代碼,特別是那些直接Ctrl+C再Ctrl+V后未做任何修改的代碼,用句時(shí)髦的話說(shuō),一點(diǎn)技術(shù)含量都沒(méi)有!所以在我們今后所要討論的內(nèi)容中,盡量會(huì)避免出現(xiàn)直接的代碼,在有些地方確實(shí)需要代碼來(lái)表述時(shí),也將會(huì)選擇使用偽碼。
  先從mangos的登錄服代碼開(kāi)始。mangos的登錄服是一個(gè)單線程的結(jié)構(gòu),雖然在數(shù)據(jù)庫(kù)連接中可以開(kāi)啟一個(gè)獨(dú)立的線程,但這個(gè)線程也只是對(duì)無(wú)返回結(jié)果的執(zhí)行類(lèi)SQL做緩沖,而對(duì)需要有返回結(jié)果的查詢類(lèi)SQL還是在主邏輯線程中阻塞調(diào)用的。
  登錄服中唯一的這一個(gè)線程,也就是主循環(huán)線程對(duì)監(jiān)聽(tīng)的socket做select操作,為每個(gè)連接進(jìn)來(lái)的客戶端讀取其上的數(shù)據(jù)并立即進(jìn)行處理,直到服務(wù)器收到SIGABRT或SIGBREAK信號(hào)時(shí)結(jié)束。
  所以,mangos登錄服主循環(huán)的邏輯,也包括后面游戲服的邏輯,主循環(huán)的關(guān)鍵代碼其實(shí)是在SocketHandler中,也就是那個(gè)Select函數(shù)中。檢查所有的連接,對(duì)新到來(lái)的連接調(diào)用OnAccept方法,有數(shù)據(jù)到來(lái)的連接則調(diào)用OnRead方法,然后socket處理器自己定義對(duì)接收到的數(shù)據(jù)如何處理。
  很簡(jiǎn)單的結(jié)構(gòu),也比較容易理解。
  只是,在對(duì)性能要求比較高的服務(wù)器上,select一般不會(huì)是最好的選擇。如果我們使用windows平臺(tái),那IOCP將是首選;如果是linux,epool將是不二選擇。我們也不打算討論基于IOCP或是基于epool的服務(wù)器實(shí)現(xiàn),如果僅僅只是要實(shí)現(xiàn)服務(wù)器功能,很簡(jiǎn)單的幾個(gè)API調(diào)用即可,而且網(wǎng)上已有很多好的教程;如果是要做一個(gè)成熟的網(wǎng)絡(luò)服務(wù)器產(chǎn)品,不是我?guī)灼?jiǎn)單的技術(shù)介紹文章所能達(dá)到。
  另外,在服務(wù)器實(shí)現(xiàn)上,網(wǎng)絡(luò)IO與邏輯處理一般會(huì)放在不同的線程中,以免耗時(shí)較長(zhǎng)的IO過(guò)程阻塞住了需要立即反應(yīng)的游戲邏輯。
  數(shù)據(jù)庫(kù)的處理也類(lèi)似,會(huì)使用異步的方式,也是避免耗時(shí)的查詢過(guò)程將游戲服務(wù)器主循環(huán)阻塞住。想象一下,因某個(gè)玩家上線而發(fā)起的一次數(shù)據(jù)庫(kù)查詢操作導(dǎo)致服務(wù)器內(nèi)所有在線玩家都卡住不動(dòng)將是多么恐怖的一件事!
  另外還有一些如事件、腳本、消息隊(duì)列、狀態(tài)機(jī)、日志和異常處理等公共組件,我們也會(huì)在接下來(lái)的時(shí)間里進(jìn)行探討。
服務(wù)器公共組件實(shí)現(xiàn) -- 繼續(xù)來(lái)說(shuō)主循環(huán)
  前面我們只簡(jiǎn)單了解了下mangos登錄服的程序結(jié)構(gòu),也發(fā)現(xiàn)了一些不足之處,現(xiàn)在我們就來(lái)看看如何提供一個(gè)更好的方案。
  正如我們?cè)懻撨^(guò)的,為了游戲主邏輯循環(huán)的流暢運(yùn)行,所有比較耗時(shí)的IO操作都會(huì)分享到單獨(dú)的線程中去做,如網(wǎng)絡(luò)IO,數(shù)據(jù)庫(kù)IO和日志IO等。當(dāng)然,也有把這些分享到單獨(dú)的進(jìn)程中去做的。
  另外對(duì)于大多數(shù)服務(wù)器程序來(lái)說(shuō),在運(yùn)行時(shí)都是作為精靈進(jìn)程或服務(wù)進(jìn)程的,所以我們并不需要服務(wù)器能夠處理控制臺(tái)用戶輸入,我們所要處理的數(shù)據(jù)來(lái)源都來(lái)自網(wǎng)絡(luò)。
  這樣,主邏輯循環(huán)所要做的就是不停要取消息包來(lái)處理,當(dāng)然這些消息包不僅有來(lái)自客戶端的玩家操作數(shù)據(jù)包,也有來(lái)自GM服務(wù)器的管理命令,還包括來(lái)自數(shù)據(jù)庫(kù)查詢線程的返回結(jié)果消息包。這個(gè)循環(huán)將一直持續(xù),直到收到一個(gè)通知服務(wù)器關(guān)閉的消息包。
  主邏輯循環(huán)的結(jié)構(gòu)還是很簡(jiǎn)單的,復(fù)雜的部分都在如何處理這些消息包的邏輯上。我們可以用一段簡(jiǎn)單的偽碼來(lái)描述這個(gè)循環(huán)過(guò)程:
    while (Message* msg = getMessage())    {      if (msg為服務(wù)器關(guān)閉消息)        break;      處理msg消息;    }
  這里就有一個(gè)問(wèn)題需要探討了,在getMessage()的時(shí)候,我們應(yīng)該去哪里取消息?前面我們考慮過(guò),至少會(huì)有三個(gè)消息來(lái)源,而我們還討論過(guò),這些消息源的IO操作都是在獨(dú)立的線程中進(jìn)行的,我們這里的主線程不應(yīng)該直接去那幾處消息源進(jìn)行阻塞式的IO操作。
  很簡(jiǎn)單,讓那些獨(dú)立的IO線程在接收完數(shù)據(jù)后自己送過(guò)來(lái)就是了。好比是,我這里提供了一個(gè)倉(cāng)庫(kù),有很多的供貨商,他們有貨要給我的時(shí)候只需要交到倉(cāng)庫(kù),然后我再到倉(cāng)庫(kù)去取就是了,這個(gè)倉(cāng)庫(kù)也就是消息隊(duì)列。消息隊(duì)列是一個(gè)普通的隊(duì)列實(shí)現(xiàn),當(dāng)然必須要提供多線程互斥訪問(wèn)的安全性支持,其基本的接口定義大概類(lèi)似這樣:
    IMessageQueue    {      void putMessage(Message*);      Message* getMessage();    }
  網(wǎng)絡(luò)IO,數(shù)據(jù)庫(kù)IO線程把整理好的消息包都加入到主邏輯循環(huán)線程的這個(gè)消息隊(duì)列中便返回。有關(guān)消息隊(duì)列的實(shí)現(xiàn)和線程間消息的傳遞在ACE中有比較完全的代碼實(shí)現(xiàn)及描述,還有一些使用示例,是個(gè)很好的參考。
  這樣的話,我們的主循環(huán)就很清晰了,從主線程的消息隊(duì)列中取消息,處理消息,再取下一條消息......
Re:游戲服務(wù)器技術(shù)交流
服務(wù)器方面我有兩個(gè)問(wèn)題,可能的話請(qǐng)樓主在后續(xù)篇章里解答一下吧:1。網(wǎng)絡(luò)協(xié)議的設(shè)計(jì)問(wèn)題。作為一個(gè)外行我一直不清楚這是否有一定的方法和技巧或者規(guī)則和約定。就我個(gè)人而言,目前我只是掌握了單個(gè)數(shù)據(jù)包的傳送和解析,單個(gè)數(shù)據(jù)包在網(wǎng)上的格式是“l(fā)en-type-data”。但是我發(fā)現(xiàn)很多時(shí)候,對(duì)于一個(gè)事務(wù),它在邏輯上是一個(gè)整體,但是卻需要在服務(wù)器和客戶端之間有多次的數(shù)據(jù)往返才能完成,目前我的做法是某一端在處理某個(gè)數(shù)據(jù)包時(shí)如果認(rèn)為需要有進(jìn)一步的通信就往對(duì)方發(fā)出一個(gè)數(shù)據(jù)包,但是我發(fā)現(xiàn)這樣的話在邏輯上是整體的一個(gè)事務(wù)需要設(shè)計(jì)多個(gè)數(shù)據(jù)包,而且這個(gè)事務(wù)的處理流程會(huì)分散在多個(gè)數(shù)據(jù)包的處理函數(shù)里,這樣的代碼就很不清晰,維護(hù)更新也很麻煩。不知道業(yè)內(nèi)在做的時(shí)候有什么方法沒(méi)有?2。持續(xù)運(yùn)行的問(wèn)題。有沒(méi)有什么辦法,使得服務(wù)器端有所更新時(shí)能盡量減少服務(wù)器端需要重新啟動(dòng)的概率?
Re:游戲服務(wù)器技術(shù)交流
len-type-data 大都是這樣,一個(gè)業(yè)務(wù)邏輯要分散在我個(gè)消息碼中處理,也大都這樣,當(dāng)然你可以用狀態(tài)機(jī)的方式,進(jìn)入一項(xiàng)業(yè)務(wù)的時(shí)候就是一個(gè)狀態(tài),這樣使得該業(yè)務(wù)的邏輯只在一個(gè)狀態(tài)中
減少服務(wù)器重啟,比較好的就是通過(guò)腳本了,簡(jiǎn)單實(shí)用,至于ACE的那個(gè)配置框架,可以支持組件的熱插拔,好像沒(méi)見(jiàn)人用過(guò),多一事不如少一事,萬(wàn)一插出毛病來(lái)了,得不償失
至于wow最近在國(guó)外測(cè)試的熱重啟,還不清楚他采用的什么技術(shù)
服務(wù)器公共組件實(shí)現(xiàn) -- 消息隊(duì)列
  既然說(shuō)到了消息隊(duì)列,那我們繼續(xù)來(lái)稍微多聊一點(diǎn)吧。
  我們所能想到的最簡(jiǎn)單的消息隊(duì)列可能就是使用stl的list來(lái)實(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)雖然簡(jiǎn)單,但功能是絕對(duì)滿足需求的,只是性能上可能稍稍有些不盡如人意。其最大的問(wèn)題在頻繁的鎖競(jìng)爭(zhēng)上。
  對(duì)于如何減少鎖競(jìng)爭(zhēng)次數(shù)的優(yōu)化方案,GhostCheng提出了一種。提供一個(gè)隊(duì)列容器,里面有多個(gè)隊(duì)列,每個(gè)隊(duì)列都可固定存放一定數(shù)量的消息。網(wǎng)絡(luò)IO線程要給邏輯線程投遞消息時(shí),會(huì)從隊(duì)列容器中取一個(gè)空隊(duì)列來(lái)使用,直到將該隊(duì)列填滿后再放回容器中換另一個(gè)空隊(duì)列。而邏輯線程取消息時(shí)是從隊(duì)列容器中取一個(gè)有消息的隊(duì)列來(lái)讀取,處理完后清空隊(duì)列再放回到容器中。
  這樣便使得只有在對(duì)隊(duì)列容器進(jìn)行操作時(shí)才需要加鎖,而IO線程和邏輯線程在操作自己當(dāng)前使用的隊(duì)列時(shí)都不需要加鎖,所以鎖競(jìng)爭(zhēng)的機(jī)會(huì)大大減少了。
  這里為每個(gè)隊(duì)列設(shè)了個(gè)最大消息數(shù),看來(lái)好像是打算只有當(dāng)IO線程寫(xiě)滿隊(duì)列時(shí)才會(huì)將其放回到容器中換另一個(gè)隊(duì)列。那這樣有時(shí)也會(huì)出現(xiàn)IO線程未寫(xiě)滿一個(gè)隊(duì)列,而邏輯線程又沒(méi)有數(shù)據(jù)可處理的情況,特別是當(dāng)數(shù)據(jù)量很少時(shí)可能會(huì)很容易出現(xiàn)。GhostCheng在他的描述中沒(méi)有講到如何解決這種問(wèn)題,但我們可以先來(lái)看看另一個(gè)方案。
  這個(gè)方案與上一個(gè)方案基本類(lèi)似,只是不再提供隊(duì)列容器,因?yàn)樵谶@個(gè)方案中只使用了兩個(gè)隊(duì)列,arthur在他的一封郵件中描述了這個(gè)方案的實(shí)現(xiàn)及部分代碼。兩個(gè)隊(duì)列,一個(gè)給邏輯線程讀,一個(gè)給IO線程用來(lái)寫(xiě),當(dāng)邏輯線程讀完隊(duì)列后會(huì)將自己的隊(duì)列與IO線程的隊(duì)列相調(diào)換。所以,這種方案下加鎖的次數(shù)會(huì)比較多一些,IO線程每次寫(xiě)隊(duì)列時(shí)都要加鎖,邏輯線程在調(diào)換隊(duì)列時(shí)也需要加鎖,但邏輯線程在讀隊(duì)列時(shí)是不需要加鎖的。
  雖然看起來(lái)鎖的調(diào)用次數(shù)是比前一種方案要多很多,但實(shí)際上大部分鎖調(diào)用都是不會(huì)引起阻塞的,只有在邏輯線程調(diào)換隊(duì)列的那一瞬間可能會(huì)使得某個(gè)線程阻塞一下。另外對(duì)于鎖調(diào)用過(guò)程本身來(lái)說(shuō),其開(kāi)銷(xiāo)是完全可以忽略的,我們所不能忍受的僅僅是因?yàn)殒i調(diào)用而引起的阻塞而已。
  兩種方案都是很優(yōu)秀的優(yōu)化方案,但也都是有其適用范圍的。GhostCheng的方案因?yàn)樘峁┝硕鄠€(gè)隊(duì)列,可以使得多個(gè)IO線程可以總工程師的,互不干擾的使用自己的隊(duì)列,只是還有一個(gè)遺留問(wèn)題我們還不了解其解決方法。arthur的方案很好的解決了上一個(gè)方案遺留的問(wèn)題,但因?yàn)橹挥幸粋€(gè)寫(xiě)隊(duì)列,所以當(dāng)想要提供多個(gè)IO線程時(shí),線程間互斥地寫(xiě)入數(shù)據(jù)可能會(huì)增大競(jìng)爭(zhēng)的機(jī)會(huì),當(dāng)然,如果只有一個(gè)IO線程那將是非常完美的。
服務(wù)器公共組件實(shí)現(xiàn) -- 環(huán)形緩沖區(qū)
  消息隊(duì)列鎖調(diào)用太頻繁的問(wèn)題算是解決了,另一個(gè)讓人有些苦惱的大概是這太多的內(nèi)存分配和釋放操作了。頻繁的內(nèi)存分配不但增加了系統(tǒng)開(kāi)銷(xiāo),更使得內(nèi)存碎片不斷增多,非常不利于我們的服務(wù)器長(zhǎng)期穩(wěn)定運(yùn)行。也許我們可以使用內(nèi)存池,比如SGISTL中附帶的小內(nèi)存分配器。但是對(duì)于這種按照嚴(yán)格的先進(jìn)先出順序處理的,塊大小并不算小的,而且塊大小也并不統(tǒng)一的內(nèi)存分配情況來(lái)說(shuō),更多使用的是一種叫做環(huán)形緩沖區(qū)的方案,mangos的網(wǎng)絡(luò)代碼中也有這么一個(gè)東西,其原理也是比較簡(jiǎn)單的。
  就好比兩個(gè)人圍著一張圓形的桌子在追逐,跑的人被網(wǎng)絡(luò)IO線程所控制,當(dāng)寫(xiě)入數(shù)據(jù)時(shí),這個(gè)人就往前跑;追的人就是邏輯線程,會(huì)一直往前追直到追上跑的人。如果追上了怎么辦?那就是沒(méi)有數(shù)據(jù)可讀了,先等會(huì)兒?jiǎn)h,等跑的人向前跑幾步了再追,總不能讓游戲沒(méi)得玩了吧。那要是追的人跑的太慢,跑的人轉(zhuǎn)了一圈過(guò)來(lái)反追上追的人了呢?那您也先歇會(huì)兒吧。要是一直這么反著追,估計(jì)您就只能換一個(gè)跑的更快的追逐者了,要不這游戲還真沒(méi)法玩下去。
  前面我們特別強(qiáng)調(diào)了,按照嚴(yán)格的先進(jìn)先出順序進(jìn)行處理,這是環(huán)形緩沖區(qū)的使用必須遵守的一項(xiàng)要求。也就是,大家都得遵守規(guī)定,追的人不能從桌子上跨過(guò)去,跑的人當(dāng)然也不允許反過(guò)來(lái)跑。至于為什么,不需要多做解釋了吧。
  環(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線程往里寫(xiě),邏輯線程在后面讀,互相追逐??梢俏覀兪褂昧饲懊娼榻B的優(yōu)化方案后,可能這里便不再需要環(huán)形緩沖區(qū)了,至少我們并不再需要他們是環(huán)形的了。因?yàn)槲覀儗?duì)同一個(gè)隊(duì)列不再會(huì)出現(xiàn)同時(shí)讀和寫(xiě)的情況,每個(gè)隊(duì)列在寫(xiě)滿后交給邏輯線程去讀,邏輯線程讀完后清空隊(duì)列再交給IO線程去寫(xiě),一段固定大小的緩沖區(qū)即可。沒(méi)關(guān)系,這么好的技術(shù),在別的地方一定也會(huì)用到的。
Re: 游戲服務(wù)器技術(shù)交流


  對(duì)于如何減少鎖競(jìng)爭(zhēng)次數(shù)的優(yōu)化方案,GhostCheng提出了一種。提供一個(gè)隊(duì)列容器,里面有多個(gè)隊(duì)列,每個(gè)隊(duì)列都可固定存放一定數(shù)量的消息。網(wǎng)絡(luò)IO線程要給邏輯線程投遞消息時(shí),會(huì)從隊(duì)列容器中取一個(gè)空隊(duì)列來(lái)使用,直到將該隊(duì)列填滿后再放回容器中換另一個(gè)空隊(duì)列。而邏輯線程取消息時(shí)是從隊(duì)列容器中取一個(gè)有消息的隊(duì)列來(lái)讀取,處理完后清空隊(duì)列再放回到容器中。
  這樣便使得只有在對(duì)隊(duì)列容器進(jìn)行操作時(shí)才需要加鎖,而IO線程和邏輯線程在操作自己當(dāng)前使用的隊(duì)列時(shí)都不需要加鎖,所以鎖競(jìng)爭(zhēng)的機(jī)會(huì)大大減少了。
對(duì)于第一條,如果網(wǎng)絡(luò)IO線程長(zhǎng)時(shí)間--填不滿一個(gè)隊(duì)列,那么這個(gè)隊(duì)列的消息是不是就無(wú)法放回容器中?假設(shè)你的網(wǎng)絡(luò)線程和邏輯線程的處理能力是一樣的,那么實(shí)際上每次網(wǎng)絡(luò)線程在處理消息的時(shí)候,邏輯線程總是取不到有消息的隊(duì)列。
鎖碰撞的機(jī)會(huì)并不取決于你加鎖的隊(duì)列有多長(zhǎng),是一個(gè)還是十個(gè),而在于你加鎖和解鎖之間代碼執(zhí)行的時(shí)間,盡管你只有一個(gè)隊(duì)列,隊(duì)列有一百個(gè)消息,但是如果只是在其中的幾行代碼加鎖,碰撞的機(jī)率依然很小。
對(duì)于第二條,你的前提是邏輯線程和網(wǎng)絡(luò)IO線程本身是各自同步執(zhí)行的,但實(shí)際上就拿網(wǎng)絡(luò)線程來(lái)講本身就有可能有多個(gè)線程在同時(shí)處理網(wǎng)絡(luò)消息,那么他們都會(huì)去你所謂的容器中尋找空的隊(duì)列,這本身就是資源競(jìng)爭(zhēng),更不用說(shuō)其它的邏輯數(shù)據(jù)了。
我個(gè)人認(rèn)為鎖的頻繁程度并不是系統(tǒng)所能控制的,但是加鎖執(zhí)行的代碼卻是可以控制的。我們可以為長(zhǎng)時(shí)間處理的代碼所需要的資源創(chuàng)建一個(gè)副本,當(dāng)我們復(fù)制副本的時(shí)候,可以將原信息加鎖,復(fù)制完成即刻解鎖,而不必要在整個(gè)處理信息的時(shí)間全部加鎖。

Re:游戲服務(wù)器技術(shù)交流
每次取一個(gè)空隊(duì)列出來(lái)后就從容器里拿掉,IO線程自己保存著使用,不是每次要寫(xiě)數(shù)據(jù)都去取隊(duì)列
至于隊(duì)列未滿不會(huì)主動(dòng)放回容器的問(wèn)題,邏輯線程可以在容器中所有隊(duì)列都為空的時(shí)候給IO線程發(fā)消息,要求所有的IO線程都立即調(diào)換隊(duì)列
Re:游戲服務(wù)器技術(shù)交流
我也沒(méi)有說(shuō)隊(duì)列長(zhǎng)了會(huì)增大鎖碰撞的機(jī)會(huì)
我說(shuō)的是讀線程和寫(xiě)線程都對(duì)同一個(gè)隊(duì)列操作會(huì)引起頻繁的鎖碰撞
而分多個(gè)隊(duì)列后,讀和寫(xiě)都只針對(duì)自己的隊(duì)列,這時(shí)就算所有的操作都加鎖,也是沒(méi)有碰撞的,碰撞只有可能發(fā)生在去容器中調(diào)換隊(duì)列時(shí)和兩個(gè)線程互換隊(duì)列時(shí)

Re:游戲服務(wù)器技術(shù)交流
關(guān)于隊(duì)列的問(wèn)題,我以前一直在想是否可能構(gòu)建一個(gè)專(zhuān)門(mén)為多線程設(shè)計(jì)的隊(duì)列,而不是現(xiàn)在這樣以隊(duì)列為基本單位進(jìn)行加鎖。我覺(jué)得大多數(shù)時(shí)候,隊(duì)首出隊(duì)和隊(duì)尾入隊(duì)是沒(méi)有多少?zèng)_突的,因?yàn)榭梢哉J(rèn)為大多數(shù)時(shí)候隊(duì)首和隊(duì)尾之間是有其他節(jié)點(diǎn)來(lái)分隔的,但是實(shí)際嘗試的時(shí)候發(fā)現(xiàn)由于入隊(duì)和出隊(duì)的操縱需要操縱一些共有的指針(比如隊(duì)首指針、隊(duì)尾指針),隊(duì)列長(zhǎng)度的判斷也需要操縱一些共有的指針,因此要達(dá)到理論上那么少的沖突一直做不到,所以我現(xiàn)在也是對(duì)整個(gè)隊(duì)列加鎖。但是畢竟理論上當(dāng)隊(duì)列中間有節(jié)點(diǎn)分隔隊(duì)首和隊(duì)尾的時(shí)候入隊(duì)和出隊(duì)是不應(yīng)該沖突的,不知道大家有什么辦法或思路。
另外關(guān)于IO緩存的問(wèn)題。對(duì)于一個(gè)網(wǎng)絡(luò)連接,recv和send都是系統(tǒng)調(diào)用,而且它們都只支持線性緩存而不支持環(huán)形緩存。如果要用循環(huán)緩存是否就必然會(huì)增加這些系統(tǒng)調(diào)用的調(diào)用次數(shù)?系統(tǒng)調(diào)用的開(kāi)銷(xiāo)似乎并不低。我現(xiàn)在是每個(gè)連接使用線性緩存,每次epoll通知有數(shù)據(jù)之后只調(diào)用一次recv,提供給recv的緩存是這個(gè)線性緩存剩下的那一段,讀完之后立即判斷緩存中是否有了完整的數(shù)據(jù)包,有的話就調(diào)用函數(shù)把它還原為一個(gè)Message對(duì)象并把這個(gè)對(duì)象加入到一個(gè)隊(duì)列里,然后把剩余的數(shù)據(jù)memcpy到緩存的頭部。而且循環(huán)緩存還有個(gè)問(wèn)題,就是其中一個(gè)完整的數(shù)據(jù)包的數(shù)據(jù)可能不是連續(xù)的,而是分布在內(nèi)存區(qū)域頭尾的分開(kāi)的兩段,而且后面一段其實(shí)是數(shù)據(jù)包的前面一段,這樣不連續(xù)的數(shù)據(jù)要還原為struct或者對(duì)象都很麻煩,特別是如果一個(gè)4字節(jié)的int被分開(kāi)了,前2個(gè)字節(jié)在緩存尾部,后2個(gè)字節(jié)在緩存頭部,那么要把這個(gè)數(shù)據(jù)還原為int就很麻煩,還是避免不了memcpy……畢竟環(huán)形緩存在底層仍然是線性的,要把環(huán)形緩存封裝為一個(gè)流可能會(huì)很麻煩。
Re:游戲服務(wù)器技術(shù)交流
不知道是誰(shuí)發(fā)明的環(huán)形緩存,我覺(jué)得這種東西用于吃回轉(zhuǎn)壽司還行,用在高速運(yùn)行的服務(wù)器估計(jì)有點(diǎn)問(wèn)題,我沒(méi)試過(guò),我只發(fā)表一下個(gè)人看法。
牛人寫(xiě)的設(shè)計(jì)游戲服務(wù)器 國(guó)外牛人小戶型設(shè)計(jì)
第一2個(gè)指針只能用于2個(gè)線程,如果用于超過(guò)2個(gè)線程,那么對(duì)這2個(gè)指針的訪問(wèn)就要加鎖,碰撞是一樣的。第二要保證讀取的指針永遠(yuǎn)不能越過(guò)寫(xiě)入的指針,對(duì)于每秒循環(huán)千萬(wàn)次的計(jì)算機(jī)來(lái)說(shuō),要做到這一點(diǎn)只能依賴(lài)于每次移動(dòng)讀取指針的時(shí)候判斷寫(xiě)入的指針是否在前,在判斷的同時(shí)要求寫(xiě)入的指針是靜止的,就是說(shuō)要對(duì)寫(xiě)入指針加鎖。第三環(huán)型緩沖區(qū)要變長(zhǎng)比較麻煩,如果環(huán)型隊(duì)列滿了,必須增加新的空間,這一點(diǎn)不如線形隊(duì)列方便。
我個(gè)人覺(jué)得緩沖區(qū)停留在內(nèi)存級(jí)別就可以了。
這是個(gè)比較有意思的問(wèn)題,我覺(jué)得服務(wù)器的問(wèn)題不在于使用什么架構(gòu),因?yàn)榧軜?gòu)總是隨著不同的應(yīng)用在變化著,而在于我們?nèi)绾谓M織數(shù)據(jù)的傳輸和疏導(dǎo),有點(diǎn)像交警。
Re:游戲服務(wù)器技術(shù)交流
隊(duì)列容器,里面有多個(gè)隊(duì)列,在我看來(lái),是為了解決邏輯線程頻繁P(pán)opMsg,使得IO線程與邏輯線程頻繁鎖沖突的問(wèn)題。(對(duì)于很多人來(lái)說(shuō),恐怕邏輯線程都是近似于不阻塞死循環(huán)一樣在PopMsg查詢是否有消息)

以隊(duì)列內(nèi)部操作為單位加鎖,用起來(lái)恐怕很麻煩,有不少類(lèi)似if(!empty())pop()else ....;的操作,我曾經(jīng)寫(xiě)過(guò)empty,pop為單位加鎖,結(jié)果實(shí)際中就遇到empy為false,執(zhí)行到pop時(shí)就是空隊(duì)列了(囧),類(lèi)似這種問(wèn)題,在多核心,多CPU機(jī)器上更是頻發(fā)。

對(duì)于bigbook2000說(shuō)的“這是個(gè)比較有意思的問(wèn)題,我覺(jué)得服務(wù)器的問(wèn)題不在于使用什么架構(gòu),因?yàn)榧軜?gòu)總是隨著不同的應(yīng)用在變化著,而在于我們?nèi)绾谓M織數(shù)據(jù)的傳輸和疏導(dǎo),有點(diǎn)像交警?!眰€(gè)人認(rèn)為,服務(wù)器還是在于架構(gòu)。這話說(shuō)的就像“程序不在于怎么去設(shè)計(jì)編寫(xiě),因?yàn)槌绦螂S著不同的應(yīng)用在變化,而在于我們?cè)趺慈ラ_(kāi)發(fā)更加很好很強(qiáng)大的新語(yǔ)言”^__^
服務(wù)器公共組件實(shí)現(xiàn) -- 發(fā)包的方式
  前面一直都在說(shuō)接收數(shù)據(jù)時(shí)的處理方法,我們應(yīng)該用專(zhuān)門(mén)的IO線程,接收到完整的消息包后加入到主線程的消息隊(duì)列,但是主線程如何發(fā)送數(shù)據(jù)還沒(méi)有探討過(guò)。
  一般來(lái)說(shuō)最直接的方法就是邏輯線程什么時(shí)候想發(fā)數(shù)據(jù)了就直接調(diào)用相關(guān)的socketAPI發(fā)送,這要求服務(wù)器的玩家對(duì)象中保存其連接的socket句柄。但是直接send調(diào)用有時(shí)候有會(huì)存在一些問(wèn)題,比如遇到系統(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ú)立的線程來(lái)處理數(shù)據(jù)發(fā)送,類(lèi)似于邏輯線程對(duì)數(shù)據(jù)的處理方式,這個(gè)獨(dú)立發(fā)送線程也維護(hù)一個(gè)消息隊(duì)列,邏輯線程要發(fā)數(shù)據(jù)時(shí)也只是把數(shù)據(jù)加入到這個(gè)隊(duì)列中,發(fā)送線程循環(huán)取包來(lái)執(zhí)行send調(diào)用,這時(shí)的阻塞也就不會(huì)對(duì)邏輯線程有任何影響了。
  采用第二種方式還可以附帶一個(gè)優(yōu)化方案。一般對(duì)于廣播消息而言,發(fā)送給周?chē)婕业臄?shù)據(jù)都是完全相同的,我們?nèi)绻捎媒o每個(gè)玩家一個(gè)緩沖隊(duì)列的方式,這個(gè)數(shù)據(jù)包將需要拷貝多份,而采用一個(gè)全局發(fā)送隊(duì)列時(shí),我們只需要把這個(gè)消息入隊(duì)一次,同時(shí)指明該消息包是要發(fā)送給哪些socket的即可。有關(guān)該優(yōu)化的說(shuō)明在云風(fēng)描述其連接服務(wù)器實(shí)現(xiàn)的blog文章中也有講到,有興趣的可以去閱讀一下。
Re: Re: Re:游戲服務(wù)器技術(shù)交流


qinglan: Re: Re:游戲服務(wù)器技術(shù)交流
全局隊(duì)列確實(shí)會(huì)有由于一個(gè)客戶端的阻塞導(dǎo)致整個(gè)隊(duì)列堵塞的情況
不知是否有好的解決方法,要沒(méi)有的話那還是傳統(tǒng)的方法,每個(gè)連接一個(gè)緩沖隊(duì)列了

全局發(fā)送隊(duì)列一開(kāi)始也想使用,優(yōu)點(diǎn)就是數(shù)據(jù)共享,后來(lái)實(shí)際運(yùn)行中發(fā)現(xiàn)問(wèn)題很多.如果數(shù)據(jù)不保發(fā)送到client,可以忽略發(fā)送錯(cuò)誤.即send后無(wú)論正確與否都直接刪除該消息.這對(duì)于UDP程序可以接受,但如果使用TCP,發(fā)送失敗意味著該連接已斷或者其他情況,如果等待發(fā)送(可能100-10000毫秒后才發(fā)送成功或者失敗),勢(shì)必對(duì)后續(xù)隊(duì)列中的消息產(chǎn)生延遲(100個(gè)連接每人send延遲100毫秒就很可怕了),所以send必須是異步發(fā)送.每次pop連接buffer中的數(shù)據(jù),異步發(fā)送數(shù)據(jù),成功后繼續(xù)pop發(fā)送余下的數(shù)據(jù),平時(shí)待發(fā)數(shù)據(jù)都push到連接buffer中,一但連接buffer數(shù)據(jù)超過(guò)一定大小,即可認(rèn)定該連接已斷線或者惡意不接受數(shù)據(jù),直接kick(當(dāng)然你也可以在send超時(shí)直接kick,但client可能只是偶爾延遲幾秒,這樣做勢(shì)必導(dǎo)致玩家常常掉線.).個(gè)人認(rèn)為有時(shí)候內(nèi)存優(yōu)化并沒(méi)有解決服務(wù)器的壓力,反而更增加了很多隱性bug.因?yàn)榫W(wǎng)絡(luò)是不確定,不可預(yù)測(cè),除了AI計(jì)算,服務(wù)器瓶頸就在發(fā)送而不是內(nèi)存上.



服務(wù)器公共組件實(shí)現(xiàn) -- 狀態(tài)機(jī)
  有關(guān)State模式的設(shè)計(jì)意圖及實(shí)現(xiàn)就不從設(shè)計(jì)模式中摘抄了,我們只來(lái)看看游戲服務(wù)器編程中如何使用State設(shè)計(jì)模式。
  首先還是從mangos的代碼開(kāi)始看起,我們注意到登錄服在處理客戶端發(fā)來(lái)的消息時(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)證通過(guò)和已認(rèn)證通過(guò)。而這個(gè)狀態(tài)標(biāo)識(shí)的改變是在運(yùn)行時(shí)進(jìn)行的,確切的說(shuō)是在收到某個(gè)消息并正確處理完后改變的。
  我們?cè)賮?lái)看看設(shè)計(jì)模式中對(duì)State模式的說(shuō)明,其中關(guān)于State模式適用情況里有一條,當(dāng)操作中含有龐大的多分支的條件語(yǔ)句,且這些分支依賴(lài)于該對(duì)象的狀態(tài),這個(gè)狀態(tài)通常用一個(gè)或多個(gè)枚舉變量表示。
  描述的情況與我們這里所要處理的情況是如此的相似,也許我們可以試一試。那再看看State模式提供的解決方案是怎樣的,State模式將每一個(gè)條件分支放入一個(gè)獨(dú)立的類(lèi)中。
  由于這里的兩個(gè)狀態(tài)標(biāo)識(shí)只區(qū)分出了兩種狀態(tài),所以,我們僅需要兩個(gè)獨(dú)立的類(lèi),用以表示兩種狀態(tài)即可。然后,按照State模式的描述,我們還需要一個(gè)Context類(lèi),也就是狀態(tài)機(jī)管理類(lèi),用以管理當(dāng)前的狀態(tài)類(lèi)。稍作整理,大概的代碼會(huì)類(lèi)似這樣:
  狀態(tài)基類(lèi)接口:  StateBase  {    void Enter() = 0;    void Leave() = 0;    void Process(Message* msg) = 0;  };
  狀態(tài)機(jī)基類(lèi)接口:  MachineBase  {    void ChangeState(StateBase* state) = 0;
    StateBase* m_curState;  };
  我們的邏輯處理類(lèi)會(huì)從MachineBase派生,當(dāng)取出數(shù)據(jù)包后交給當(dāng)前狀態(tài)處理,前面描述的兩個(gè)狀態(tài)類(lèi)從StateBase派生,每個(gè)狀態(tài)類(lèi)只處理該狀態(tài)標(biāo)識(shí)下需要處理的消息。當(dāng)要進(jìn)行狀態(tài)轉(zhuǎn)換時(shí),調(diào)用MachineBase的ChangeState()方法,顯示地告訴狀態(tài)機(jī)管理類(lèi)自己要轉(zhuǎn)到哪一個(gè)狀態(tài)。所以,狀態(tài)類(lèi)內(nèi)部需要保存狀態(tài)機(jī)管理類(lèi)的指針,這個(gè)可以在狀態(tài)類(lèi)初始化時(shí)傳入。具體的實(shí)現(xiàn)細(xì)節(jié)就不做過(guò)多描述了。
  使用狀態(tài)機(jī)雖然避免了復(fù)雜的判斷語(yǔ)句,但也引入了新的麻煩。當(dāng)我們?cè)谶M(jìn)行狀態(tài)轉(zhuǎn)換時(shí),可能會(huì)需要將一些現(xiàn)場(chǎng)數(shù)據(jù)從老狀態(tài)對(duì)象轉(zhuǎn)移到新?tīng)顟B(tài)對(duì)象,這需要在定義接口時(shí)做一下考慮。如果不希望執(zhí)行拷貝,那么這里公有的現(xiàn)場(chǎng)數(shù)據(jù)也可放到狀態(tài)機(jī)類(lèi)中,只是這樣在使用時(shí)可能就不那么優(yōu)雅了。
  正如同在設(shè)計(jì)模式中所描述的,所有的模式都是已有問(wèn)題的另一種解決方案,也就是說(shuō)這并不是唯一的解決方案。放到我們今天討論的State模式中,就拿登錄服所處理的兩個(gè)狀態(tài)來(lái)說(shuō),也許用mangos所采用的遍歷處理函數(shù)的方法可能更簡(jiǎn)單,但當(dāng)系統(tǒng)中的狀態(tài)數(shù)量增多,狀態(tài)標(biāo)識(shí)也變多的時(shí)候,State模式就顯得尤其重要了。
  比如在游戲服務(wù)器上玩家的狀態(tài)管理,還有在實(shí)現(xiàn)NPC人工智能時(shí)的各種狀態(tài)管理,這些就留作以后的專(zhuān)題吧。
服務(wù)器公共組件 -- 事件與信號(hào)
關(guān)于這一節(jié),這幾天已經(jīng)打了好幾遍草稿,總覺(jué)得說(shuō)不清楚,也不好組織這些內(nèi)容,但是打鐵要趁熱,為避免熱情消退,先整理一點(diǎn)東西放這,好繼續(xù)下面的主題,以后如果有機(jī)會(huì)再回來(lái)完善吧。本節(jié)內(nèi)容欠考慮,希望大家多給點(diǎn)意見(jiàn)。
有些類(lèi)似于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類(lèi)似,對(duì)于事件我們可以重定義其處理方法,甚至過(guò)濾掉某些事件使其不被處理,但對(duì)于信號(hào)我們只是收到了一個(gè)通知,有些類(lèi)似于Observe模式中的觀察者,當(dāng)收到更新通知時(shí),我們只能更新自己的狀態(tài),對(duì)剛剛發(fā)生的事件我不已不能做任何影響。
仔細(xì)來(lái)看,事件與信號(hào)其實(shí)并無(wú)多大差別,從我們對(duì)其需求上來(lái)說(shuō),都只要能注冊(cè)事件或信號(hào)響應(yīng)函數(shù),在事件或信號(hào)產(chǎn)生時(shí)能夠被通知到即可。但有一項(xiàng)區(qū)別在于,事件處理函數(shù)的返回值是有意義的,我們要根據(jù)這個(gè)返回值來(lái)確定是否還要繼續(xù)事件的處理,比如在QT中,事件處理函數(shù)如果返回true,則這個(gè)事件處理已完成,QApplication會(huì)接著處理下一個(gè)事件,而如果返回false,那么事件分派函數(shù)會(huì)繼續(xù)向上尋找下一個(gè)可以處理該事件的注冊(cè)方法。信號(hào)處理函數(shù)的返回值對(duì)信號(hào)分派器來(lái)說(shuō)是無(wú)意義的。
簡(jiǎn)單點(diǎn)說(shuō),就是我們可以為事件定義過(guò)濾器,使得事件可以被過(guò)濾。這一功能需求在游戲服務(wù)器上是到處存在的。
關(guān)于事件和信號(hào)機(jī)制的實(shí)現(xiàn),網(wǎng)絡(luò)上的開(kāi)源訓(xùn)也比較多,比如FastDelegate,sigslot,boost::signal等,其中sigslot還被Google采用,在libjingle的代碼中我們可以看到他是如何被使用的。
在實(shí)現(xiàn)事件和信號(hào)機(jī)制時(shí)或許可以考慮用同一套實(shí)現(xiàn),在前面我們就分析過(guò),兩者唯一的區(qū)別僅在于返回值的處理上。
另外還有一個(gè)需要我們關(guān)注的問(wèn)題是事件和信號(hào)處理時(shí)的優(yōu)先級(jí)問(wèn)題。在QT中,事件因?yàn)槎际桥c窗口相關(guān)的,所以事件回調(diào)時(shí)都是從當(dāng)前窗口開(kāi)始,一級(jí)一級(jí)向上派發(fā),直到有一個(gè)窗口返回true,截?cái)嗔耸录奶幚頌橹?。?duì)于信號(hào)的處理則比較簡(jiǎn)單,默認(rèn)是沒(méi)有順序的,如果需要明確的順序,可以在信號(hào)注冊(cè)時(shí)顯示地指明槽的位置。
在我們的需求中,因?yàn)闆](méi)有窗口的概念,事件的處理也與信號(hào)類(lèi)似,對(duì)注冊(cè)過(guò)的處理器要按某個(gè)順序依次回調(diào),所以優(yōu)先級(jí)的設(shè)置功能是需要的。
最后需要我們考慮的是事件和信號(hào)的處理方式。在QT中,事件使用了一個(gè)事件隊(duì)列來(lái)維護(hù),如果事件的處理中又產(chǎn)生了新的事件,那么新的事件會(huì)加入到隊(duì)列尾,直到當(dāng)前事件處理完畢后,QApplication再去隊(duì)列頭取下一個(gè)事件來(lái)處理。而信號(hào)的處理方式有些不同,信號(hào)處理是立即回調(diào)的,也就是一個(gè)信號(hào)產(chǎn)生后,他上面所注冊(cè)的所有槽都會(huì)立即被回調(diào)。這樣就會(huì)產(chǎn)生一個(gè)遞歸調(diào)用的問(wèn)題,比如某個(gè)信號(hào)處理器中又產(chǎn)生了一個(gè)信號(hào),會(huì)使得信號(hào)的處理像一棵樹(shù)一樣的展開(kāi)。我們需要注意的一個(gè)很重要的問(wèn)題是會(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è)坑,希望能夠有所交流。
Re:游戲服務(wù)器技術(shù)交流
我一般是使用Command模式的:一、如果是與網(wǎng)絡(luò)另一端的節(jié)點(diǎn)交流,那么就發(fā)送一個(gè)Command對(duì)象給對(duì)方;二、如果是本地交流:(1).如果是同步的,那么就只是調(diào)用目標(biāo)對(duì)象的函數(shù);(2.)如果是異步的,那么就會(huì)生成一個(gè)Command對(duì)象,并且把它加入到隊(duì)列里,然后在游戲循環(huán)中會(huì)有專(zhuān)門(mén)的一步來(lái)處理這個(gè)隊(duì)列里所有的Command對(duì)象。
管理Command對(duì)象的那個(gè)隊(duì)列,我把它封裝為MessageRouter,從網(wǎng)絡(luò)連接那里讀取到的Command對(duì)象也會(huì)push進(jìn)入MessageRouter。偽碼:

class Command{public:……virtual ~Command();virtual boolprocess(void);//這里process函數(shù)的參數(shù)也可以是某個(gè)對(duì)象的引用,通過(guò)它能夠得到大多數(shù)所需要的數(shù)據(jù)virtual bool load();virtual boolsave();//這里的load和save是對(duì)象序列化函數(shù),用于從網(wǎng)絡(luò)上收取Command或者發(fā)送Command};
class MessageRouter{public:void push( Command* );void process(){for( each cmd ){if( cmd->process() ){erase( cmd );}}}protected:std::list _cmds;};


另外也可以在MessageRouter里加入時(shí)間或其他的狀態(tài)來(lái)觸發(fā)或抑制Command的process的調(diào)用。

Re:游戲服務(wù)器技術(shù)交流
事件機(jī)制我一般只針對(duì)客戶端,服務(wù)器端重來(lái)不搞這些東西,服務(wù)器端我個(gè)人習(xí)慣全部使用switch-case,交給腳本或者其他模塊去處理,只有少數(shù)系統(tǒng)消息被過(guò)濾,其他一概不管,而且客戶端的事件機(jī)制全部都要放到隊(duì)列中排隊(duì),盡管COM支持多線程,但DX經(jīng)常出現(xiàn)Crash,那種研究客戶端多線程的人,我只能表示佩服,自己是沒(méi)有那個(gè)精力搞。
我也不習(xí)慣把一個(gè)事件交給多個(gè)對(duì)象處理,類(lèi)似Windows消息機(jī)制,子窗口響應(yīng),子窗口的子窗口還響應(yīng),這個(gè)在游戲中也很危險(xiǎn),除了在底層的少數(shù)消息我自己處理,其他的邏輯上我僅僅處理一次,如果需要多個(gè)對(duì)象同時(shí)處理一個(gè)消息,由邏輯自己傳遞消息處理指針,我不在網(wǎng)絡(luò)模塊實(shí)現(xiàn)他。
Re:游戲服務(wù)器技術(shù)交流
sjinny的command隊(duì)列與事件隊(duì)列其實(shí)也無(wú)多少區(qū)別吧,只是command封裝的更好些,事件只是個(gè)簡(jiǎn)單通知
6377同學(xué)一直在說(shuō)只看看,但似乎又想說(shuō)點(diǎn)什么,難道是要我弄點(diǎn)排場(chǎng)來(lái)請(qǐng)一下?
bigbook2000說(shuō)的不使用事件通知而使用switch-case,這應(yīng)該算是編碼習(xí)慣問(wèn)題吧,本身event也好,signal也好,observer也好,就是為了模塊間解耦,用switch-case當(dāng)然什么都能解決,但似乎揉的太緊了
再談登錄服的實(shí)現(xiàn)
離我們的登錄服實(shí)現(xiàn)已經(jīng)太遠(yuǎn)了,先拉回來(lái)一下。
關(guān)于登錄服、大區(qū)服及游戲世界服的結(jié)構(gòu)之前已做過(guò)探討,這里再把各自的職責(zé)和關(guān)系列一下。
GateWay/WorldServer GateWay/WodlServer LoginServer LoginServerDNSServer 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ú)立的世界服或者通過(guò)網(wǎng)關(guān)連接到后面的世界服。
在mangos的代碼中,我們注意到登錄服是從數(shù)據(jù)庫(kù)中取的世界列表,而在wow官方服務(wù)器中,我們卻會(huì)注意到,這個(gè)世界服列表并不是一開(kāi)始就固定,而是動(dòng)態(tài)生成的。當(dāng)每周一次的維護(hù)完成之后,我們可以很明顯的看到這個(gè)列表生成的過(guò)程。剛開(kāi)始時(shí),世界列表是空的,慢慢的,世界服會(huì)一個(gè)個(gè)加入進(jìn)來(lái),而這里如果有世界服當(dāng)機(jī),他會(huì)顯示為離線,不會(huì)從列表中刪除。但是當(dāng)下一次服務(wù)器再維護(hù)后,所有的世界服都不存在了,全部重新開(kāi)始添加。
從上面的過(guò)程描述中,我們很容易想到利用一個(gè)臨時(shí)的列表來(lái)保存世界服信息,這也是我們?cè)黾覹orldServerMgr服務(wù)器的目的所在。GateWay/WorldServer在啟動(dòng)時(shí)會(huì)自動(dòng)向WorldServerMgr注冊(cè)自己,這樣就把自己所代表的游戲世界添加到世界列表中了。類(lèi)似的,如果DNSServer也可以讓LoginServer自己去注冊(cè),這樣在臨時(shí)LoginServer時(shí)就不需要去改動(dòng)DNSServer的配置文件了。
WorldServerMgr內(nèi)部的實(shí)現(xiàn)很簡(jiǎn)單,監(jiān)聽(tīng)一個(gè)固定的端口,接受來(lái)自WorldServer的主動(dòng)連接,并檢測(cè)其狀態(tài)。這里可以用一個(gè)心跳包來(lái)實(shí)現(xiàn)其狀態(tài)的檢測(cè),如果WorldServer的連接斷開(kāi)或者在規(guī)定時(shí)間內(nèi)未收到心跳包,則將其狀態(tài)更新為離線。另外WorldServerMgr還處理來(lái)自LoginServer的列表請(qǐng)求。由于世界列表并不常變化,所以LoginServer沒(méi)有必要每次發(fā)送世界列表時(shí)都到WorldServerMgr上去取,LoginServer完全可以自己維護(hù)一個(gè)列表,當(dāng)WorldServerMgr上的列表發(fā)生變化時(shí),WorldServerMgr會(huì)主動(dòng)通知所有的LoginServer也更新一下自己的列表。這個(gè)或許就可以用前面描述過(guò)的事件方式,或者就是觀察者模式了。
WorldServerMgr實(shí)現(xiàn)所要考慮的內(nèi)容就這些,我們?cè)賮?lái)看看LoginServer,這才是我們今天要重點(diǎn)討論的對(duì)象。
前面探討一些服務(wù)器公共組件,那我們這里也應(yīng)該試用一下,不能只是停留在理論上。先從狀態(tài)機(jī)開(kāi)始,前面也說(shuō)過(guò)了,登錄服上的連接會(huì)有兩種狀態(tài),一是帳號(hào)密碼驗(yàn)證狀態(tài),一是服務(wù)器列表選擇狀態(tài),其實(shí)還有另外一個(gè)狀態(tài)我們未曾討論過(guò),因?yàn)樗c我們的登錄過(guò)程并無(wú)多大關(guān)系,這就是升級(jí)包發(fā)送狀態(tài)。三個(gè)狀態(tài)的轉(zhuǎn)換流程大致為:
LogonState -- 驗(yàn)證成功 -- 版本檢查 -- 版本低于最新值 -- 轉(zhuǎn)到UpdateState|-- 版本等于最新值 -- 轉(zhuǎn)到WorldState
這個(gè)版本檢查的和決定下一個(gè)狀態(tài)的過(guò)程是在LogonState中進(jìn)行的,下一個(gè)狀態(tài)的選擇是由當(dāng)前狀態(tài)來(lái)決定。密碼驗(yàn)證的過(guò)程使用了SRP6協(xié)議,具體過(guò)程就不多做描述,每個(gè)游戲使用的方式也都不大一樣。而版本檢查的過(guò)程就更無(wú)值得探討的東西,一個(gè)if-else即可。
升級(jí)狀態(tài)其實(shí)就是文件傳輸過(guò)程,文件發(fā)送完畢后通知客戶端開(kāi)始執(zhí)行升級(jí)文件并關(guān)閉連接。世界選擇狀態(tài)則提供了一個(gè)列表給客戶端,其中包括了所有游戲世界網(wǎng)關(guān)服務(wù)器的IP、PORT和當(dāng)前負(fù)載情況。如果客戶端一直連接著,則該狀態(tài)會(huì)以每5秒一次的頻率不停刷新列表給客戶端,當(dāng)然是否值得這樣做還是有待商榷。
整個(gè)過(guò)程似乎都沒(méi)有值得探討的內(nèi)容,但是,還沒(méi)有完。當(dāng)客戶端選擇了一個(gè)世界之后該怎么辦?wow的做法是,當(dāng)客戶端選擇一個(gè)游戲世界時(shí),客戶端會(huì)主動(dòng)去連接該世界服的IP和PORT,然后進(jìn)入這個(gè)游戲世界。與此同時(shí),與登錄服的連接還沒(méi)有斷開(kāi),直到客戶端確實(shí)連接上了選定的世界服并且走完了排隊(duì)過(guò)程為止。這是一個(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è)不自覺(jué)的玩家不遵守游戲規(guī)則,沒(méi)有去驗(yàn)證帳號(hào)密碼就直接跑去連接世界服了,就如同一個(gè)不自覺(jué)的乘客沒(méi)有換登機(jī)牌就直接跑到登機(jī)口一樣。這時(shí),乘務(wù)員會(huì)客氣地告訴你要先換登機(jī)牌,那登機(jī)牌又從哪來(lái)?檢票口換的,人家會(huì)先驗(yàn)明你的身份,確認(rèn)后才會(huì)發(fā)給你登機(jī)牌。一樣的處理過(guò)程,我們的登錄服在驗(yàn)明客戶端身份后,也會(huì)發(fā)給客戶端一個(gè)登機(jī)牌,這個(gè)登機(jī)牌還有一個(gè)學(xué)名,叫做sessionkey。
客戶端拿著這個(gè)sessionkey去世界服網(wǎng)關(guān)處就可正確登錄了嗎?似乎還是有個(gè)疑問(wèn),他怎么知道我這個(gè)key是不是造假的?沒(méi)辦法,中國(guó)的假貨太多,我們不得不到處都考慮假貨的問(wèn)題。方法很簡(jiǎn)單,去找給他登機(jī)牌的那個(gè)檢票員問(wèn)一下,這張牌是不是他發(fā)的不就得了??墒?,那么多的LoginServer,要一個(gè)個(gè)問(wèn)下來(lái),這效率也太低了,后面排的長(zhǎng)隊(duì)一定會(huì)開(kāi)始叫喚了。那么,LoginServer將這個(gè)key存到數(shù)據(jù)庫(kù)中,讓網(wǎng)關(guān)服自己去數(shù)據(jù)庫(kù)驗(yàn)證?似乎也是個(gè)可行的方案。
如果覺(jué)得這樣給數(shù)據(jù)庫(kù)帶來(lái)了太大的壓力的話,也可以考慮類(lèi)似WorldServerMgr的做法,用一個(gè)臨時(shí)的列表來(lái)保存,甚至可以將這個(gè)列表就保存到WorldServerMgr上,他正好是全區(qū)唯一的。這兩種方案的本質(zhì)并無(wú)差別,只是看你愿意將負(fù)載放在哪里。而不管在哪里,這個(gè)查詢的壓力都是有點(diǎn)大的,想想,全區(qū)所有玩家呢。所以,我們也可以試著考慮一種新的方案,一種不需要去全區(qū)唯一一個(gè)入口查詢的方案。
那我們將這些session key分開(kāi)存儲(chǔ)不就得了。一個(gè)可行的方案是,讓任意時(shí)刻只有一個(gè)地方保存一個(gè)客戶端的sessionkey,這個(gè)地方可能是客戶端當(dāng)前正連接著的服務(wù)器,也可以是它正要去連接的服務(wù)器。讓我們來(lái)詳細(xì)描述一下這個(gè)過(guò)程,客戶端在LoginServer上驗(yàn)證通過(guò)時(shí),LoginServer為其生成了本次會(huì)話的sessionkey,但只是保存在當(dāng)前的LoginServer上,不會(huì)存數(shù)據(jù)庫(kù),也不會(huì)發(fā)送給WorldServerMgr。如果客戶端這時(shí)想要去某個(gè)游戲世界,那么他必須先通知當(dāng)前連接的LoginServer要去的服務(wù)器地址,LoginServer將sessionkey安全轉(zhuǎn)移給目標(biāo)服務(wù)器,轉(zhuǎn)移的意思是要確保目標(biāo)服務(wù)器收到了sessionkey,本地保存的要?jiǎng)h除掉。轉(zhuǎn)移成功后LoginServer通知客戶端再去連接目標(biāo)服務(wù)器,這時(shí)目標(biāo)服務(wù)器在驗(yàn)證sessionkey合法性的時(shí)候就不需要去別處查詢了,只在本地保存的session key列表中查詢即可。
當(dāng)然了,為了session key的安全,所有的服務(wù)器在收到一個(gè)新的sessionkey后都會(huì)為其設(shè)一個(gè)有效期,在有效期過(guò)后還沒(méi)來(lái)認(rèn)證的,則該 session key會(huì)被自動(dòng)刪除。同時(shí),所有服務(wù)器上的sessionkey在連接關(guān)閉后一定會(huì)被刪除,保證一個(gè)session key真正只為一次連接會(huì)話服務(wù)。
但是,很顯然的,wow并沒(méi)有采用這種方案,因?yàn)榭蛻舳嗽谶x擇世界服時(shí)并沒(méi)有向服務(wù)器發(fā)送要求確認(rèn)的消息。wow中的sessionkey應(yīng)該是保存在一個(gè)類(lèi)似于WorldServerMgr的地方,或者如mangos一樣,就是保存在了數(shù)據(jù)庫(kù)中。不管是怎樣一種方式,了解了其過(guò)程,代碼實(shí)現(xiàn)都是比較簡(jiǎn)單的,我們就不再贅述了。
有關(guān)登錄服的討論或許該告一段落了吧

  

愛(ài)華網(wǎng)本文地址 » http://www.klfzs.com/a/25101016/311634.html

更多閱讀

多人聚會(huì)可以玩哪些小游戲? 精 公司聚會(huì)小游戲

多人聚會(huì)可以玩哪些小游戲? 精——簡(jiǎn)介在節(jié)假日的時(shí)候,很久未見(jiàn)的朋友同學(xué)們都會(huì)從四處相聚到一起。聯(lián)絡(luò)下感情,在聚會(huì)的時(shí)候愛(ài)玩的朋友同學(xué)常會(huì)組織一些好玩的小游戲來(lái)活躍一下氣氛,再次回憶一下曾經(jīng)的快樂(lè)時(shí)光。下面給大家分享幾個(gè)好

展示設(shè)計(jì)理念 展柜的設(shè)計(jì)說(shuō)明

展示設(shè)計(jì)是藝術(shù)設(shè)計(jì)領(lǐng)域中具有復(fù)合性質(zhì)的設(shè)計(jì)形式之一。在客觀上,它融合了二維、三維、四維等設(shè)計(jì)因素;在主觀上,它是信息及其特定時(shí)空關(guān)系的規(guī)劃和實(shí)施。本章從概念的認(rèn)同、特征的分析、范圍的認(rèn)定和展示設(shè)計(jì)的風(fēng)格等四個(gè)方面闡述展

轉(zhuǎn)載 關(guān)于商戰(zhàn)明有感,總體寫(xiě)的不錯(cuò),但我和小姐的關(guān) 寫(xiě)的不錯(cuò)

原文地址:關(guān)于商戰(zhàn)明有感,總體寫(xiě)的不錯(cuò),但我和小姐的關(guān)系顯然是猜想作者:商戰(zhàn)明關(guān)于商戰(zhàn)明有感商戰(zhàn)自從接觸商戰(zhàn)明師兄以來(lái),遇到過(guò)這樣那樣的不理解,一個(gè)一個(gè)的問(wèn)題慢慢沉淀下來(lái),經(jīng)過(guò)兩個(gè)月的思考,很多東西慢慢有了輪廓。為什么他有兩個(gè)圈

現(xiàn)代人寫(xiě)古詩(shī)詞 現(xiàn)代人寫(xiě)的文言文

現(xiàn)代人寫(xiě)的古詩(shī)詞,不少令人愛(ài)看,有的還讓人耐看,即是還不時(shí)反復(fù)叨念,以致把它自然記住。如悼念周總理的詩(shī):“欲悲聞鬼叫,我哭豺狼笑。灑淚祭雄杰,揚(yáng)眉劍出鞘?!痹谀莻€(gè)年代,正義之情不容抒發(fā),但祭奠總理之時(shí),已是群眾覺(jué)醒之際。又如聶紺弩的

聲明:《牛人寫(xiě)的設(shè)計(jì)游戲服務(wù)器 國(guó)外牛人小戶型設(shè)計(jì)》為網(wǎng)友紅鶯綠柳分享!如侵犯到您的合法權(quán)益請(qǐng)聯(lián)系我們刪除

国产美女www免费| 成人av在线中文字幕一区| 久久久久亚洲成高清少妇| 欧美精品久久久999| 人妻精品人妻一区二区三区四五| 亚洲国产三级网站| 国产偷拍自拍久久久| 久久久999国产视频| 亚洲国产182tv精品天堂| 久久亚洲精品人成综合网| 精品久久久久久久毛片微露脸| 天天操天天色天天爱| 99久久精品视频免费| 在线成人亚洲中文字幕av| 青青青青青青青青草视频在线观看 | 国产成人综合精品久久| 中文字幕麻豆韩日在线| 国产av一二区三区| 久久青草视频免费播放| www操操操操操操| 蜜臀久久精品99国产| 五月天丁香一区二区三区| 国产精品久久久久久久影视一免费| 精品久久久久久一区二| 91精品视频一区二区| 日b视频在线免费| 精品乱码久久久久久| 午在线亚洲男人午在线| 国产精品亚洲av资源| 91国产手机在线观看| 欧美激情精品久久久小说| 婷婷六月天狠狠爱| 91精品国产高清自在线| 国产熟妇精品一区二区三区| 亚洲美女色www色| 蜜臀久久精品99国产| 欧美日韩特一级大片| 日韩黄页网站在线免费观看视频| 男人做受天堂青青操| 熟女人妻中文字幕专区| evanotty精品二区| 伊人成色综合视频| 日韩欧美成年一级| 九九热精品免费视频观看| 日韩一级特黄大片亚洲| 久久va视频免费观看| 日b视频在线免费| 粉嫩一区二区三区在线观看| 日韩中文字幕三级电影| 伊人久久大综合网站| 亚洲人午夜精品射精日韩| 丝袜人妻丝袜美腿呻吟| 精品视频一区二区三区蜜桃 | 国内精品 一区二区三区| 日韩午夜宅男福利| 人妻av瑟瑟在线| 2020国产成人精品视频vr| 中文字幕福利在线视频| 97人澡人人添人人爽欧美| 把人妻干哭中文字幕在线观看| 日韩人妻精品免费| 亚洲视频色图天堂| 女同精品人妻一区二区三区| 九九视频精品在线免费观看| 国产av熟女白浆精品视频| 熟女少妇水多一区二区三区| 亚洲午夜久久久久影院| 日韩av亚洲激情色图| 欧美人妻有码中文字幕| 国产精品久久久久久成人免费| 8日韩一级一片内射视9一 | 成人caopao自拍视频| 中文字幕人妻乱码在线| 日本不卡三区四区| 麻豆www久久国产精品| 全部免费特黄特色大片看片| 丝袜美腿aⅴ一区二区三区| 国产av一区二区三区免费视频| 亚洲男人天堂网在线看| 国产成人av在线无限观看| 亚洲一区二区日韩电影| 欧美成人精品女人久久久| 中文字幕av一区二区人妻| 亚洲成人精品国产av| 亚洲高清精品人妻自拍| 99啪免费观看在线视频| 天天插天天透天天婷婷| 久久久久久综合国语对白| 日本女人视频网站| 欧美激情一区二区三区综合| 91在线精品小视频| www中文字幕日本| 久久精品美女性感国产综合av| 久久亚洲福利视频免费| 精品视频一区二区三区蜜桃| 性欧美精品久久久久久久樱花| 欧美丰满熟妇乱xxxx| 国精产品一区一区三区漫画| 天天看亚洲特黄大片| 成人精品漫画h动漫日本| 91久久精品国产91久| 国产一区二三区日韩精品| 亚洲日韩不卡视频色酷色| 日韩欧美成年一级| 一区二区三区日韩在线观看| 久久久久久精品免费免费WE | 东京热日韩电影一区二区| 日韩av毛片观看| 久久人妻少妇av嫩草| 免费欧美一二三区| 欧美中文字幕在线观看免费| 日韩成人黄色av在线观看| 日韩精品久久日日躁夜夜| 瑟瑟韩漫在线观看| 日本熟妇色97一本在线观看| 精品久久久久久久久久久换人妻| 久久999精品久久久久久| 人妻熟女av一区| 国产精品成人久久久久久| 欧美精产国品一二三类产品| 色五五月五月开亚洲婷婷| 亚洲欧美日韩精品制服| 国产欧美电影一区二区三区 | 国产av熟女白浆精品视频| 国产一区二三区日韩精品| 中文字幕人妻丝袜成熟久久 | 青青草万部激情影院| 亚洲免费在线久久92| 中文字幕人妻熟女| 国产一区二区三区精品公司| 12av一区二区三区| 黄色av成人在线观看| 12av一区二区三区| 日韩人妻视频一区二区三区| 成人蜜桃美臀九一一区二区三区| 日韩av一区二区三区蜜桃| 超碰国产在线观看91| 成年人在线黄色片片网| 欧美色综合天天久久| 亚洲激情国产专区| 亚洲三级天堂在线| 国产精选一区二区三区91| 777精品午夜一区二区毛片| 人妻丰满精品熟女| 污在线观看视频一区| 欧美激情日韩精品久久久| av一区二区在线观看完| 中文字幕超碰在线播放| 五月婷婷激情在线视频播放| 97久久碰国产精品夜| 亚洲av日韩av专区国产| 在线视频中文字幕 日韩| 亚洲综合色网自拍| 国产精品久久久久久人妻免费| 久久综合亚洲精品五区| 色综合变态另类777| 国产熟妇一区二区三区av| 12av一区二区三区| 亚洲五月天久久久噜噜噜噜| 欧美日韩人妻最新入口| jizzjizz在线观看亚洲| 一区二区三区日韩在线观看| 国产人妻aⅴ一区二区三区| 久久久久久久人妻av| 7788人妻精品免费| 日本综合久久综合久久| 国产 欧美日韩在线视频| 蜜桃成熟的在线观看视频| 久久久久黄色片三级伦理| 中文字幕人妻国产91| 天天干天天色天天摸| 2014天天操一操天天干一干| 久久国产三级黄色片| 中文字幕人妻熟女| 午夜精品一区二区三区电影..| 国产99精品综合电影| 国产视频在线看一区| 日韩av成人一区二区三区在线看| evanotty精品二区| av午夜久久久久久久| 久久国产劲爆^v内射| 中文字幕在线日韩人妻| 欧美成人黑人在线观看| 中文人妻视频免费在线99| 国产亚洲成人av在线播放| 精品国产av色哟哟| 中文字幕在线日韩人妻| 日韩一区二区av在线| 99精品人妻一区二区三区| 欧美久久久久久久久久久久久| 欧美综合激情另类专区| 伊人久久中文字幕人妻| 亚久久久久久久久久久久久久| www久久久大香蕉| 午夜影院在线精品| 国产精品99久久久久www| 全亚洲最大资源网| 亚洲国产日韩精品视频| 久久久亚洲视频播放| 国产精品女主播av| 亚洲熟妇欲色一区一区三区| 最新 国产 精品 精品 视频| 国产麻豆精品传媒av国产网址 | 全部免费特黄特色大片看片| 日韩黄页网站在线免费观看视频| www操操操操操操| 国产一区二区三区高清视频| 亚洲一区二区尻逼| 日韩色图在线影院| 欧美色综合天天久久| 亚洲精品高清视频在线观看| 少妇人妻一级视频观看| 精品久久久久久久毛片微露脸| 久久久亚洲视频播放| 成人午夜精品久久av| 亚洲热青春视频在线| 99热这里只有精品色| 亚洲激情av电影| 国产又粗又猛又黄又爽又无遮挡| 国产综合精品久久东京热| 国产成+人+综合+欧美 亚洲| 人妻精品一区二区熟女| 99精品国产高清久久久久久| 成人黄色在线观看91| a阿v视频在线观看| 亚洲av在线观看播放| 中文字幕第一页婷婷| 中文字幕亚洲日韩欧美一区| 五月免费婷婷影院在线 | 久久精品国产99久久久蜜桃| 国产欧美电影一区二区三区 | 亚洲一级黄免费视频| 欧美中文字幕在线观看免费| 把人妻干哭中文字幕在线观看| 在线免费观看完整版日韩av| 精品国产av色哟哟| 日日橹狠狠爱欧美| 亚洲少妇插b色图| 国产又粗又爽又大又黄视频| 日韩av精彩在线观看| 欧美日韩国产专区一区 | 中文字幕高清资源网| 自拍偷拍另类色图| 一本色道久久综合狠狠躁篇怎么玩| 亚洲五月天久久久噜噜噜噜| 欧美久久久久久久久久久久久 | www操操操操操操| 久久久久久亚洲av在线播放| 国产人妻aⅴ一区二区三区 | 中文字幕成人乱码视频| 日韩在线中文字幕免费| 蜜臀av国内精品久久久夜夜嗨| 欧美激情精品久久久小说| 日本第一中文字幕官网| 国产麻豆精品成人免费观看| 亚洲综合激情av| 亚洲成人精品国产av| 性欧美精品久久久久久久樱花| 九九九九九九久久久久久久久久| 久久99爱精品999| 国产又粗又白又嫩又爽| 日韩影片 欧美激情| 日韩人妻字幕在线| 久久久久久综合国语对白| 丁香花激情五月资源| 婷婷麻豆国产在线观看| 国产区资源在线观看| 2020精品极品色视频| 日本人妻制服诱惑| 蜜桃久久久久久久久久久久| 欧美日韩精品在线色图| 久久精品久久久久久久久精品| 亚洲欧美日韩清纯唯美| 国产又粗又白又嫩又爽| 天天操天天爱天天操天天爱| www操操操操操操| 亚洲国产日韩精品视频| 亚洲图库另类图片日韩| 久久综合亚洲精品五区| 日日摸夜夜添精品人人妻人人| 婷婷激情激情五月天| 日本女人性开放视频| 在线观看免费日本不卡一二区| 五十路丰满大屁股老熟女| 亚洲美女色www色| 成熟丰满熟妇xxxxx丰满| 美女精品视频一区二区三区 | 超级碰碰碰91免费看| 人妻一区二区三区88av| 人人精品,人人妻| 五月激情四射综合| 欧美一区二区三区四区大片| 亚洲第一成人在线观看av| 欧美久久久久久久久久久久久| 欧美性色aⅴ欧美综合色| 国产一区二区美女视频| 精品一区二区三区熟女少妇| 久久艹中文字幕丝袜| 少妇极品熟妇人妻丰满| 国产精品日视频不卡| 国产亚洲自拍色老头| 精品久久久久久久毛片微露脸| 日本女人性开放视频| 伊人 久久 中文字幕| 在线视频蜜桃视频| 看吊视频一区二区三| 熟妇人妻久久中文字幕番号| 亚洲精品黄av人在线观看| 久久久久久精品一级片| 人妻人人干青青草| 91久久久精品免费| 亚洲成人激情图区| 亚洲自拍偷拍动图| 日韩精品日韩精品日韩精品| 五十路丰满大屁股老熟女| 亚洲国产精品国自产拍张津瑜| 中文字幕亚洲一区嗯嗯| 中文字幕乱码一区二区av| 国产精品久久久久久66| 91青青草手机视频在线观看| 精品久久99在线观看| 丝袜美腿aⅴ一区二区三区| 两个97年失恋疗伤在线观看| 国产精品国产成人生活片| 东北熟女天天日天天添| 中老熟妇一区二区| 大香蕉大香蕉大香蕉最新| a3k9x在线观看| 在线成人亚洲中文字幕av| 欧美口爆亚洲口爆在线| 国产一区二区三区在线h| 男人的天堂亚洲2020| 精品少妇人妻一区二区三区四区| 久久精品国产亚洲精品166m| 天天碰天天摸天天干天天操 | 日韩国产中文字幕人妻| 天天干天天操天天射天天| 中文字幕人妻熟女| 日本av电影av| 成人国内精品视频在线观看日韩| 国产精品99久久黑人免费| 白石茉莉奈一区二区av| 成人自拍视频手机免费在线观看 | 久久久国产精品视频在线| 一区二区三区精品少妇人妻| 2023av在线视频| 欧美日韩极品妻在线观看| 日韩欧美中文字幕少妇| 久久艹中文字幕丝袜| 两个97年失恋疗伤在线观看| 中文字幕人妻在线视频| 在线视频蜜桃视频| 欧美成人四级中文字幕| 国产一区二区三区 久久| 成人中文字幕乱码中文字幕| 伊人成色综合视频| 午夜激情四射88| 婷婷在线免费视频观看| 亚洲综合伦理av| 国产又粗又猛又爽又大的视频| 久久精品国产免费观看频道| 日韩精品视频网站免费看| 国产精品女主播av| 久久99热在线观看| 女人18毛片一区二区三区| 久久久精品亚洲一区二区三区| 亚洲激情国产专区| 一区二区三区久久久无| 风流老熟女一区二区三区av| 超碰成人手机免费在线观看| 天堂网免费在线电影| 人妻一区二区三区久久夜夜嗨 | 日韩一区二区中文字幕| 免费人成黄页网站大全在线观看| 亚洲少妇插b色图| 午夜伊人狠狠av| 人妻丰满熟妇av无码区ll| 女人18毛片一区二区三区| 婷婷激情激情五月天| 免费一区二区三区视频| 国产欧美日韩两性在线观看| 国产精品国产成人生活片| 五十路丰满大屁股老熟女| 国产精品兄妹在线观看麻豆| 97超碰在线免费在线观看| 日韩三级电影大全中文字幕| 午在线亚洲男人午在线| 日韩人妻精品免费| 在线免费观看完整版日韩av | 一区二区三区四区五区日韩| 蜜桃久久久久久久91| 久久精品亚洲天堂av| 国产美女www免费| 丁香婷婷激情啪啪综合五月天| 欧美oldman色老头| 2020精品极品色视频| 国产精产国品一二三产区视频| 久久艹中文字幕丝袜| 精品国产18久久久久久依依影院 | 五月天综合av影院| 中文字幕第一页婷婷| 玩弄放荡人妻少妇精品| 自拍偷拍图片专区| 奇米成人av电影| 伊人网免费看黄片| 91九色蝌蚪蜜桃臀| 亚洲第一成人在线观看av| 亚洲日本精品久久久久中文| 色综合久久久久久久久中文| 激情视频网站久久婷婷| 99精品国产高清久久久久久| 91综合精品久久久久| 国产一区日本一区欧美一区| 91免费观看国产精品| avtt天堂网久久精品| 福利视频一区二区 三区| 人妻熟女av一区| 乱码久久久久久久电影 | 97视频人人做人人爱| 久久精品一区二区麻豆| 亚洲国产区男人本色| 欧美色综合天天久久| 人妻在线视频福利| 97色伦综合在线欧美视频| 中文字幕人妻在线视频| 2023av在线视频| 日韩欧美激情免费无毒| 久久国产三级黄色片| 国产丝袜玉足一区二区三区性色| 国产av一区两区三区| 日本欧美人体视频| 99成人免费视频观看| 亚洲自拍 校园春色| 人人妻人人爽久久久精品软件 | 成人国产av精品麻豆网| 香蕉av蜜臀av一区二区| 日韩欧美中文字幕综合网| 蜜臀99精品国产高清在线观看| 国产精品稀缺资源av在线| 青青草万部激情影院| 日韩啪啪 中文字幕| 岛国福利视频在线观看| 蜜臀精品国产91内射久久| 午夜中文字幕a区b| 亚洲自拍 校园春色| 国产精品99久久黑人免费| 日本精品久久久久中文字幕2| 亚洲激情国产专区| 色99色.com| 亚洲精品日韩在线观看17c| 蜜桃臀久久久蜜桃臀| 亚洲成人av熟妇人妻| 国产成人综合精品久久| 日韩中文亚洲字幕av| 91中文字幕在线观看网站| 中文字幕乱码一区二区av| 午夜精品男人天堂av| 淫秽网站在线播放| 九九热在线免费视频观看| 中文字幕一区二区三区四区的| 性色av蜜臀av夜夜嗨av| 亚洲情爱视频网站| 亚洲91久久久久久久久久久| 成人精品漫画h动漫日本| 亚洲午夜青青草久久久久| 日日爱亚洲一区av| 超级碰碰碰91免费看| 人妻伦伦精品一区二区三区在线看| 熟妇人妻一区二区三区四区久久久| evanotty精品二区| 国产成人精品日本亚洲777| 丰满大屁股熟妇偷拍| 日韩午夜小视频合集| 欧美激情在线久久久| 亚洲成人三级黄色片| 伊人久久大综合网站| 蜜臀久久精品99国产| 99热在线只有精品6| 最新99热这里只有精品| 成人国产偷拍自拍视频| 亚洲热青春视频在线| 熟女少妇水多一区二区三区| 国产人妻aⅴ一区二区三区| 全亚洲最大资源网| 久久99久久99精品欧美激情| 五十路丰满大屁股老熟女| 中文字幕一区二区三区四区的| 欧美日韩国产专区一区| 国产偷拍自拍久久久| 一道精品视频一区二区三区视频| chinese中国av| 高清一区二区三区四区免费视频 | 国产美女精品传媒在线观看| 日韩亚洲成人aα在线| 日本东京热最新中文字幕| 99亚洲国产成人精品| 蜜臀99精品国产高清在线观看| 欧美一区二区三区在线精品观看| 久久99精品色婷婷| 人妻精品一区二区熟女| 天天操天天色天天爱| 欧美日韩极品妻在线观看| 久草在在线免视频在线观看| 人妻精品区三免费视频| 91在线视频在线视频在线播放| 久久精品一区二区日韩| 日韩av在线电影免费看| 欧美中文字幕在线观看免费| 日韩av毛片观看| 午夜精品男人天堂av| 国产一国产精品免费播放| 污视频18在线观看| 免费人妻人人干视频| 久久综合久久综合亚洲| 日本成人有码在线 中文字幕| 视频一视频二视频三| 蜜臀av国内精品久久久夜夜嗨| 久久资源站中文字幕| 清纯唯美激情亚洲天堂| 日日日夜夜夜精品| 日韩av中文一区| 成人亚洲一区二区三区在线观看| 日本午夜高清在线| 日韩av有码在线观看| 日韩不卡一区二区在线观看| 91人妻人人妻人人妻| av最新资源在线观看| 国产午夜精品在线免费观看| 国精产品一区一区三区漫画| 久久精品亚洲天堂av| 精品999高清视频| 麻豆高清视频在线免费观看| 亚洲天堂 亚洲第一| 天堂亚洲国产av| 精品久久久久久一区二| 精品成人一区二区三区在线看片| 亚洲av毛片在线| 亚洲少妇插b色图| 日日爱亚洲一区av| 精品少妇人妻一区二区三区四区| 色婷婷狠狠禁久久| 五月天婷亚洲天综合网鲁鲁鲁| 亚洲av在线观看播放| 性高潮久久久久久久久久| 国产一国产精品免费播放| 国产91久久久久久久免费| 国产视频日韩欧美一卡二卡 | 日韩熟妇人妻中文字幕一区| 日韩午夜小视频合集| 最新在线不卡av| www.777麻豆网| 久久久久久精品一级片| 欧美日韩亚洲精品视频| 免费看av中文字幕| 日韩亚洲欧美中文高清在线| 亚洲男人天堂网在线看| 日韩av成人一区二区三区在线看| 中文字幕人妻熟女一区二区 | 日本一区二区三区久久| 国产精品99久久久久久久vr| 老熟妇一区,二区,三区| 91精品色综合久久久蜜桃臀| 日韩熟妇人妻中文字幕一区| 日韩女优av网站在线| 人人妻人人爽人人艹| 亚洲av毛片av| 熟女少妇内色日韩亚洲| 99热在线免费这里只有精品| 麻豆xxx乱女少妇精品潘甜甜| 大香蕉久久久久在线伊人| 男人操女人的大逼逼| 性欧美精品久久久久久久樱花| 蜜臀久久精品99国产| 婷婷六月天狠狠爱| 人妻少妇一区二区三区视频| 国产香蕉特级一区二区三区| 日本东京热最新中文字幕| 天堂亚洲国产av| 男人操女人的大逼逼| 在线视频99re| 欧美日韩亚洲免费一区二区| 成年人在线黄色片片网| 免费视频亚洲中文字幕在线| 99啪免费观看在线视频| 欧美综合激情另类专区| 日本av电影av| 成人自拍视频手机免费在线观看 | 人妻少妇蜜桃视频欧美一区| 最新国产精品av| 色综合久久东京热| 久久99热久久99这里有精品| 日本一区二区三区久久| 日韩av不卡电影在线观看| 人妻视频一区二区三区免费| 伊人免费视频12| 91一区区二区三区在线观看91| 中文字幕人妻熟女av| 蜜桃成熟的在线观看视频| 2020精品极品色视频| 自拍偷拍 国产自拍| 色网站在线免费观看视频| 亚洲国产av不卡婷婷| 亚洲午夜伦理aaa| 精品综合久久久久久久91精品| 亚洲成人av熟妇人妻| 中老熟妇一区二区| 中文字幕一区二区久久人妻女| 99成人免费视频观看| 日韩草草草草草草草草草| 2023av在线视频| 精品久久久久久一区二| 老熟妇一区,二区,三区| 午夜影院在线精品| 亚洲热青春视频在线| 久草在在线免视频在线观看| 亚久久久久久久久久久久久久| 高清欧美精品xxxxx在线看| 综合久久精品久久精品| 亚洲国产精品久久久久蜜桃噜噜| 国产成+人+综合+欧美 亚洲| 亚洲精品综合免费| 中文字幕精品人妻97| 国产极品嫩模在线观看91| 亚洲成人三级黄色片| 蜜臀av性久久一区二区| 97色伦综合在线欧美视频| 在线观看日产av网站| 91久久久福利视频| 中文字幕人妻熟女一区二区| 亚洲情色电影网站| 成人亚洲一区二区三区在线观看| 亚洲综合激情av| 久久精品亚洲天堂av| 日韩精品在线免费观看自拍视频| 亚洲综合色网自拍| 亚洲激情在线电影观看| 日日橹狠狠爱欧美| 成人午夜精品久久av| 日韩美女高潮视频网站| 国产九色91中文在线视频| 亚洲久久久999| 在线视频中文字幕 日韩| 日韩av高清电影手机在线观看| 99成人免费视频观看| 久久精品 视频一区| 国产精品久久久人妻午夜| 亚州欧美中文日韩| 污视频18在线观看| 人人澡人人澡人人妻| 激情五月天福利婷婷| 欧美亚日韩一区二区三区| 日本东京热最新中文字幕| 制服丝袜 亚洲一区二区三区| 国产美女精品传媒在线观看| 少妇人妻中文字幕一二三区| 欧美成人精品女人久久久| 最新中文字幕日韩av| 亚洲自拍 校园春色| 国产精品免费看久久久久久| 人人妻人人爽久久久精品软件| 国产精品女主播av| 一本色道久久亚洲精品av| 熟女阿高潮合集91| 肥臀大腚沟肥臀大屁股一区二区| 风流老熟女一区二区三区av| 中文字幕日韩一区二区三区本高| 91香蕉久久久久久| 淫秽网站在线播放| 操穴电影中文字幕人妻中文字幕| 亚洲男人天堂2024| 97久久国产综合网| 久久天天躁夜夜躁狠狠综合网| 91在线国产精品免费观看| 五月天天天操天天干| 麻豆www久久国产精品| 蜜臀av性久久一区二区| 久久天天躁狠狠躁夜夜躁免费观看| 国产精品午夜久久久久| 亚洲欧美日韩久久精品狠狠| 日韩男叉女下面视频| 五月激情四射综合| 熟女人妻中文字幕专区| 91 porny九色| 黑人性高潮免费视频| 日本久久在线一区| se五月天天久久亚洲| 亚洲欧美自拍另类日韩| 久久精品综合一区二区三区| 日韩av在线电影免费看| 日韩一区二区三区蜜桃av| 91综合精品久久久久| 久久久久久久久久久一级片| 午夜影院成人福利| 黄色大片黄色一级大片| 国产91精品天堂在线观看| 天天操天天射天天干b| 中文字幕福利在线视频| 日本超熟老熟妇网站| 7788人妻精品免费| 人妻av精品一区| 91一区区二区三区在线观看91| 蜜桃精品一区二区在线看| 国产乱子伦视频观看| 久久国产精品99国产精2021| 制服丝袜 亚洲一区二区三区| 少妇精品久久久久久av蜜桃| 漂亮人妻被强中文字幕在线 | 精品国产日韩高清毛片| 蜜桃视频日韩欧美北条麻妃| 亚洲国产区男人本色| 熟探花啪啪第十场av| 亚洲国产182tv精品天堂| 国产又粗又白又嫩又爽| 凹凸国产av熟女白浆| 国产视频在线精品视频| 欧美日韩人妻最新入口| 成人伦理片免费在线观看免费观看 | 国产亚洲欧洲一区二区在线| 日韩中文字幕人妻在线视频| 国产偷拍自拍久久久| 欧美综合激情另类专区| 日本亚洲国产色图| 69无人区码一码二码三码| 奇米成人av电影| 午在线亚洲男人午在线| 麻豆vpswindows精品| 海角91成人一区二区三区| 成人日韩视频中文字幕| 久久久激情伦理在线视频| 欧美日韩国产精品欧美| 国产又粗又猛又爽又黄又大| 中文字幕福利在线视频| 在线国产偷拍自拍| 97人澡人人添人人爽欧美| 色片在线观看国产| 五月婷婷开心之中文字幕| 97超碰在线公开在线看免费| 人妻少妇视频在线播放| 色99色.com| 欧美美熟妇激情一区二区三区在线| 国产日韩av一区二区三区四区| 国产日韩欧美自拍视频| 人妻夜夜爽天天爽欧美色院| 中文字幕一区三区二区国产| 99热在线只有精品6| 国内精品视频一区二区三| 亚洲精选在线视频| 欧美一区二区三区四区大片| 亚洲成人激情图区| 一区二区三区久久久av| 亚洲高清电影一区| 99热这里只有精品色| 高清露脸爆极品白富美av| 99久在线视频观看| 热久久久久这里有精品| 波婷五月激情五月天| 中文字幕一区二区人妻5566| 久久久中文字幕视频| 亚洲熟妇欲色一区一区三区| 五月天久久伊人欧美| 91成人资源在线资源站| 大香蕉久久精品99| 国产 日韩 精品 欧美| 国产一区二区不卡老阿姨| 放荡的人妻少妇视频| 欧美精产国品一二三类产品| 日韩av高清电影手机在线观看| 中文字幕精品一区二区三区完整版| 亚洲一区二区三区四区五区福利| 久久综合网站亚洲av| 999国内精品视频在线观看| 91夜色私人影院在线观看| 精品国产18久久久久久依依影院| 精品999高清视频| 国产成年人精品在线看| 久久99热在线观看| 日本熟妇厨房xxxⅹ乱| 国产精品年轻夫妻激情啪啪| 日本在线丰满人妻| 99啪免费观看在线视频| 五月天综合av影院| 亚洲国产182tv精品天堂| 婷婷六月天综合久久| 97日韩在线免费视频网站| 五月婷婷大香蕉日韩| 九九九九九高清一本无码| 首页av在线观看| 日韩精品视频三级| 视频二区 中文字幕 人妻中文| 日韩av高清电影手机在线观看| 少妇极品熟妇人妻丰满| 日韩av高清在线影院| 五月婷婷亚洲综合色| 色婷婷狠狠禁久久| 国产偷拍自拍久久久| 天天看亚洲特黄大片| 日本不卡三区四区| 日韩最新p片中文字幕av| 天天摸天天高潮天天爽| brazzerss色欧美| 日韩综合一区二区三区| 五月天中文字幕在线婷婷| 污视频18在线观看| 国产精品中文字幕观看| 国产精品午夜久久久久| 亚洲av毛片av| 超碰国产在线观看91| 日韩亚洲中文字幕视频| 亚洲欧美日韩wwwc0m666| 国产又粗又猛又黄又爽又无遮挡| 日本熟妇厨房xxxⅹ乱| 久久精品一区二区日韩| 欧美美熟妇激情一区二区三区在线| 国产美女啪啪18禁| 中文字幕人妻一区二区在线av| 日韩4级视频在线播放| 国产午夜精品在线免费观看| 一道精品视频一区二区三区视频| 亚洲欧洲成熟熟女妇专区乱| 国产又粗又硬又大又长又爽| 久久av少妇av高潮| 91综合精品久久久久| 中文字幕久久人妻被中出一区精品| 老熟女av老熟女xx| 人妻精品区三免费视频| 色9933av精品一区| 欧美成人四级中文字幕| 久久精品国产亚洲精品166m| 九九热在线播放视频| www.777麻豆网| 黄色av成人在线观看| 丁香婷婷色五月激情综合深爱| 最新日韩av手机在线观看| 不卡一二三区在线视频| 日韩av有码在线观看| 国产亚洲精品久久久久久妇女| 亚洲欧美日韩国产都市激情| 深田咏美亚洲一区二区| 青青草万部激情影院| 女同精品人妻一区二区三区| 久久久久999久久久久| 欧美色综合天天久久| 综合久久精品久久精品| 久久久亚洲熟妇熟女内射一区 | 亚洲午夜青青草久久久久| 91精品一区二区三区| 国产综合精品久久东京热| 亚洲精品国品乱码久久久久| evanotty精品二区| 瑟瑟免费在线观看| 国产又粗又猛又黄又爽又无遮挡| 在线观看日产av网站| 日韩精品视频在线网站| 人妻少妇一区二区三区视频| 国产97色在线免费看| 日韩黄色影视大全| 日韩专区第17页| 国内女人精品一区二区三区| 国产美女啪啪18禁| 久久99热这里都是精品| 女人18毛片一区二区三区| 国产一区二区三区 久久| 欧美精品久久久999久久久| 国产一区二区三区 久久| 日本综合久久综合久久| 人妻视频一区二区三区免费| 久久精品熟女亚洲AV色欲男同| 99成人免费视频观看| 波多野结衣乳喷高潮视频| 岛国福利视频在线观看| 成人在线视频免费国产| 国产91久久久久久久免费| 日本一区二区三区久久| 91入口在线观看天天| 色视频免费在线观看高清| 熟女人妻中文字幕欧美日韩| 五月婷婷激情久久久| 绝色少妇高潮3在线观看| 欧美一区二区三区在线精品观看| 日韩欧美一级二级三级| 色婷婷中文字幕一区二区| 亚洲精品国品乱码久久久久| 国产又粗又硬又大又长又爽| 中文字幕亚洲日韩欧美一区| 欧美在线视频一区二区三区| 97网在线视频免费播放| 99在线观看视频在线播放| 男人操女人的大逼逼| 久久人妻少妇av嫩草| 99久久热这里只有精品| 日韩成人免费电影在线| 国产精品久久久久久66| 国产精品久久久人妻午夜| 麻豆91免费视频网站| 欧美激情在线久久久| 日韩亚洲欧美在线com| 亚洲精选在线视频| 加勒比东京热综合久久| 污在线观看视频一区| 亚洲国产区男人本色| 伊人久久首页精品| 九九热在线播放视频| 亚洲欧美日韩wwwc0m666 | 在线观看日产av网站| av中文字幕一区久久| 免费看av中文字幕| 日本女同性恋激情视频| av一区二区在线观看完| 激情五月天福利婷婷| 国产一区二区三区在线呻吟视频| 久久久999视频视频| 欧美日韩精品在线色图| 国产偷拍自拍久久久| 亚洲中文字幕久久久av| 国产精品久久久久久66| 欧美国产精品久久久久久免费| 亚洲精品国产呦系列| 久久久久性免费视频| 日本成人有码在线 中文字幕| 日韩三级电影大全中文字幕| 熟女一区二区三区在线观看视频 | 欧美日韩图区一区二区三区| 日本熟妇久久久久久| 日韩一级特黄大片亚洲| 亚洲a在线免费视频| 在线视频人妻中文字幕| 久久国产三级黄色片| 成人caopao自拍视频| 国产综合91天堂亚洲国产| 亚洲欧美日韩国产成人综合 | 午夜久久久久久禁播电影| 国产美女精品传媒在线观看| 午夜精品一区二区三区四区| 欧美日韩国产精品合集| 91久久久久久亚洲精品| 精品91爱爱中文字幕| 国产一区二区美女视频| 国产男人天堂久久精品| 久久久麻豆一区二区三区| 国产丝袜玉足一区二区三区性色| 欧美精品日韩精品亚洲| 欧美v日韩v亚洲v最新| 亚洲国产欧美精品久久久久| 伊人99久久婷婷国产视频| 五十路丰满大屁股老熟女| 99成人免费视频观看| 国产精品久久网址大全| 国产一区二区三区在线呻吟视频| 五月婷婷激情久久久| 99热这里只有精品色| 中文字幕麻豆韩日在线| 日本女人视频网站| 丰满大屁股熟妇偷拍| 亚洲av日韩在线免费观看| 51vv精品视频在线观看| 人妻少妇蜜桃视频欧美一区| 国内精品国产三级国产a久久| 中国巨乳美女的性与色| 日韩不卡av电影网| 久久综合精品乱码中文| 天堂影院在线免费观看| 亚洲一区二区三区中文久久| 狠狠做深爱婷婷综合激情| 亚洲男人天堂2024| 亚洲男人的天堂av2017| 99热这里只有精品16| 97精品久久久久中文字幕| 精品国产一区二区三区av天堂| 日韩一卡二卡三不卡| 日本加勒比免费高清视频| 国产av一区二区三区免费观看| 欧美日韩久久久久久久久| 日韩中文字幕一二| 亚洲激情四射五月| 亚洲国产日韩精品视频| 91婷婷国产精品久久久久| 人妻精品一区二区熟女| 麻豆www久久国产精品| 中文字幕人妻99| 亚洲熟妇欲色一区一区三区| 日韩在线中文字幕免费| 熟妇人妻无乱码中文字幕蜜桃| 污在线观看视频一区| 91精品国产高清自在线| 国精产品一区一区三区漫画| 亚洲欧美日韩一区一区| 黄色亚洲电影网站在线观看| 97超碰在线观看日韩| 91精品啪在线观看国产91蜜桃| 日韩亚洲欧美在线com| av中文字幕一区久久| 91中文字幕在线观看网站| 久久99热这里都是精品| 91精品一区二区在线观看久久久| 热久久久久这里有精品| 日韩一级精品一区二区| 亚洲欧美在线色视频| 绿帽人妻精品一区二区粉嫩av| 国产亚洲欧美视频一区二区| 夏天香蕉如何保存能放更久 | 国产综合精品久久东京热| 亚洲欧美日韩久久精品狠狠| 一区二区三区久久久无| 亚洲精品久久久中文字| 精品高清在线观看免费观看| 加勒比图片区不卡97| 黄色大片黄色一级大片| 日本成人有码在线 中文字幕| 久久999精品久久久久久| 国产精品自拍偷拍p| 日韩丝袜一区av| brazzerss色欧美| 93成人在线播放视频| 9999久久久久久久久| 久久久9视频免费观看| 久久天天躁狠狠躁夜夜av| 在线日韩亚洲av电影| 国产亚洲欧洲一区二区在线| 中文字幕在线人妻| 少妇高潮久久久久久一代女皇| 日韩三级视频大全| 2023av在线视频| 国产99福利小视频在线播放| 日本欧美人体视频| 亚洲成人精品国产av| 日韩精品视频网站免费看| 久久人妻少妇av嫩草| 亚洲精品国产呦系列| 久久久999久久国产| 日韩一区二区三区成人| 成人蜜桃美臀九一一区二区三区| 国产精品久久网址大全| 亚洲成人另类综合| 五月婷婷激情在线视频播放| 欧美丰满熟妇乱xxxx| 日本久久激情视频| 亚洲激情四射五月| 日韩激情视频在线高清| 久久夜夜一区二区三区日韩| 欧美精产国品一二三类产品| 人妻精品区三免费视频| 操日本熟女春宵视频| 99久久久精品四川精品| 人妻人人干青青草| 在线免费观看完整版日韩av| 国产精品久久久久久7777| 亚洲日本成人三级少妇| 日韩成人免费电影在线| 日韩精品视频三级| 亚洲精品久久久中文字| 精品999高清视频| 久久夜夜一区二区三区日韩| 熟女一区二区三区在线观看视频| 熟女少妇内色日韩亚洲| 韩日av电影在线观看| 日韩成人一区电影| av中文字幕在线观看播放| 日韩亚洲欧美在线com| 日韩一卡二卡三不卡| 日韩色图在线影院| 丁香婷婷色五月激情综合深爱| 中文字幕人妻熟女av| 人妻少妇精品一二三区| 国内一区二区三区在线观看| 中文字幕人妻一区二区在线av| 成熟丰满熟妇xxxxx丰满| www,夜色,com| 人妻一区二区三区久久夜夜嗨| 熟女少妇内色日韩亚洲| 青青青在线观看国产| 久久亚洲在线精品视频| 日本少妇人妻系列| 麻豆91免费视频网站| 91精品一区二区在线观看久久久| 国产精品久久久久jk制服| 成人小视频在线播放| 91中文字幕在线观看网站| 亚洲国产三级网站| 色秘乱码一区二区三区在线| 日韩欧美成年一级| 日韩在线中文字幕免费| 在线视频蜜桃视频| 欧美精品在线小视频| 性色av蜜臀av夜夜嗨av| 亚洲一区二区三区四区五区福利| 凹凸国产av熟女白浆| chinese中国av| 国产精品久久久久久66| 99热都是只有精品| 久久精品亚洲天堂av| 中文字幕一区二区三区四区的| 久久久亚洲视频播放| 国产久精品搜索视频| 一区二区三区久久久av| 又色又爽又黄久久98| 成人黄色在线观看91| 欧美精品在线小视频| 成人伦理片免费在线观看免费观看| 日韩影片 欧美激情| 男人的天堂精品久久| 超碰国产在线观看91| 亚洲欧美自拍另类日韩| 性欧美精品久久久久久久樱花| 久久久亚洲熟女精品俱乐部| 色综合久久久久久久久中文| 中文字幕在线日韩人妻| 日韩一区二区综合视频| 亚洲av毛片在线| 伊人久久中文字幕人妻| 99久久精品国内盗摄| 国产一区二区青青精品久久 | 国产 日韩 欧美片| 久久亚洲在线精品视频| 色哟哟 日韩精品| 亚洲欧洲成熟熟女妇专区乱| 国产一二三区不在卡| 性做久久久久久久久浪潮| 中文字幕av一区二区人妻| 天天操天天射天天干b| 视频一视频二视频三| 五月婷婷开心之中文字幕| 亚洲美女色www色| 波多野结衣乳喷高潮视频| 国产成人午夜一区二区三区| 2020精品极品色视频| 欧美国产精品久久久久久免费| 久久久久久久人妻av| 91亚洲精品在线免费观看| 青青青青久久久久久| 狠狠干狠狠操天天日| 91是什么意思网络污词| 人妻视频一区二区三区免费| 国自产久久久久无码春色影视| 久久久999久久国产| 九九电影欧美精品免费看| 中文字幕日韩一区二区不卡| 亚洲情色电影网站| 天天干天天操天天射天天| 亚洲午夜青青草久久久久| 亚洲三级自拍视频| 九九九九九高清一本无码| 亚洲制服人妻另类小说| 99热6这里只有精品国产| 国产精品美女久久av爽| 女同精品人妻一区二区三区| 91麻豆精品传媒国产在线观看| 久草在在线免视频在线观看| 精品一区二区三区国产馆| 99久久久精品四川精品| 中文字幕人妻丝袜成熟久久| 制服丝袜 欧美日韩| 息子嫁中文字幕一区二区三区| 中文字幕人妻国产91| 精品少妇人妻一区二区三区四区 | 视频一视频二视频三| 丰满少妇免费做爰大片人| 久久内射天天玩天天懂色| 91入口在线观看天天| 日韩欧美成年一级| 日韩中文字幕系列有码精品视频 | 免费人妻人人干视频| 日韩草草草草草草草草草| www久久久大香蕉| 国产av天堂亚洲国产av在线| 93成人在线播放视频| 人妻人人干青青草| 日韩黄页网站在线免费观看视频| 全部免费特黄特色大片看片| 丰满少妇一区二区三区视频| 精品无人区无码乱码毛片国产| 97超碰在线公开在线看免费| 国产丝袜玉足一区二区三区性色| av一区二区在线观看完| 亚洲热青春视频在线| 91精品一区二区三区| 国产免费av在线网站| 在线日韩av永久免费观看| 最新在线不卡av| 色婷婷 激情五月| 国产精品久久网址大全| 99热都是只有精品| 亚洲丰满性熟妇ⅹxxoo| 国产熟妇一区二区三区av| 人妻少妇一区二区三区视频| av福利免费在线看| 精品视频一区二区三区蜜桃| 高清一区二区三区四区免费视频| 在线视频99re| 国产一区二区三区在线观看网站| 最新国产精品av| 91精品一区二区三区| 五月婷婷中文字幕综合网| 中文字幕人妻在线视频| 蜜桃成熟的在线观看视频| 国产成人综合精品久久| 国产精品三级久久久久精品大全| 亚洲综合激情av| 久久久精品亚洲一区二区三区| 97超碰在线公开在线看免费| 蜜桃久久久久久久91| 久久99国产日韩精品久久99| 日韩美女av一区| 人妻一区二区三区88av| 超级碰碰碰91免费看| 午夜香蕉一区二区三区| 91综合精品久久久久| 天堂久久天堂色综合色| 欧美一区二区三区无| 精品久久久久久久久久久换人妻 | 激情五月天福利婷婷| 五月婷婷大香蕉日韩| 亚洲制服人妻另类小说| 青青久视频在线观看| 黑夜中文字幕首页在线视频| 日韩人妻字幕在线| 无码人妻一区二区三区18| 日本六十路xxx| 国产一区二区三区四区99| 伊人久久首页精品| 在线观看国产一区亚洲| 成人午夜精品久久av| 日韩一级特黄大片亚洲| 91九色蝌蚪蜜桃臀| 日韩毛片在线视频播放| 风流老熟女一区二区三区av| www一区二区三区视频com| a3k9x在线观看| 国产精品美女丝袜一区二区| 五月天婷亚洲天综合网鲁鲁鲁| 中文字幕91大神| 黑人操中国女人的逼| 日韩国产中文字幕人妻| 网友自拍成人在线视频| 一本久久综合亚洲| 加勒比东京热综合久久| 国产精品99久久久久www| 久久99热在线观看| av天堂网在线播放| 亚洲a在线免费视频| 国内一区二区三区在线观看| 日本不卡三区四区| 国产69堂一区二区三区在线观看| 九九电影欧美精品免费看| 亚洲激情国产专区| 日韩综合一区二区三区| 久久av少妇av高潮| 亚洲少妇人妻系列| 欧美精品久久久999久久久| 久久99久久99久久99受| 蜜桃av一区二区视频| 亚洲一级黄免费视频| 人妻夜夜爽天天爽欧美色院| 日韩精品中文字幕巨臀人妻中出| 丝袜人妻丝袜美腿呻吟| 在线视频中文字幕 日韩| 91行情视频在线看高清| 亚洲一级黄免费视频| 91在线国产精品免费观看| 精品无人区无码乱码毛片国产| 自拍偷拍图片专区| 成人av在线中文字幕一区| 成人免费电影网站一区二区三区| 久久久激情伦理在线视频| 性色av蜜臀av夜夜嗨av| 绿帽人妻精品一区二区粉嫩av| 国产日韩在线成人免费视频| 中文字幕超碰在线播放| 秋霞福利视频在线观看| 日韩av一级大片| 综合网站久久久久久| 久久久久9999免费视频| evanotty精品二区| 91精品国产久久久久久| 91色porny在线| 亚洲日本精品久久久久中文| 在线观看免费日本不卡一二区| 加勒比图片区不卡97| 亚洲AV无码国产综合一区二区| 国产一区二区三区在线呻吟视频| 九九久久精品免费网站| 国产日韩av在线免费观看| 美女亚洲第一区二区| 麻豆精品国产一二三免费| 日韩欧美亚洲成人网| a3k9x在线观看| 国产极品嫩模在线观看91| 九九视频精品在线免费观看| 国产女人久久久久久| 99在线观看视频在线播放| 中老熟妇一区二区| www,夜色,com| 熟女少妇水多一区二区三区| 色婷婷综合久久久久精品中文| 中文字幕福利在线视频| 日韩一区二区三区蜜桃av| 秋霞福利视频在线观看| 熟妇人妻久久中文字幕番号| 黄色亚洲电影网站在线观看| 日本 亚洲 久久| av资源中文字幕在线| 91行情视频在线看高清| www,夜色,com| 国产综合精品久久东京热| 五月婷婷激情久久久| 久久re视频在线免费观看| 日韩精品久久日日躁夜夜| 国产亚洲欧美色视频| 婷婷在线免费视频观看| 不卡无在一区二区三区四区| 奇米成人av电影| 一级av黄色大片| 久久综合亚洲精品五区| 日本一区二区三区久久| 国产一区二区三区精品公司| 国产一区二区三区精品公司| 中文字幕一区二区三区四区的| 56porm在线视频| 日韩毛片公交车上激情| 日韩毛片在线视频播放| 狠狠干狠狠操天天日| 欧美一区二区三区四区大片 | 日韩黄色大片中文字幕| 亚洲精品人码av| 人妻熟妇丰满不伦一区二区三区| 亚洲午夜久久久久影院| 欧美日韩图区一区二区三区| 亚洲一区二区五十路熟女激情中出| 精品在线免费观看av| 91超碰精品日日躁夜夜躁欧美| 人人精品,人人妻| evanotty精品二区| 亚洲国产日韩精品视频| 久久99热这里都是精品| 一道精品视频一区二区三区视频| 伊人免费视频12| 2020精品极品色视频| 清纯唯美激情亚洲天堂| 青青青青青青青青草视频在线观看| 一本色道久久亚洲精品av| 日韩免费视频精品| 91xxx免费在线观看| 99这里有精品在线观看视频| 中日亚洲欧美激情在线| 蜜桃久久久久久久91| 久久综合九色综合欧洲98| 国产精品6久久久久久久| 日韩精品久久日日躁夜夜| 免费一区二区三区视频| 精品丝袜久久久久久人妻懂色| av成人影院在线播放| 超碰97人人看人人爱| 最新99热这里只有精品| av资源中文字幕在线| 青青久视频在线观看| 亚洲国产中文二区二区| 麻豆www久久国产精品| 精品国产18久久久久久依依影院| 欧美激情一区二区三区综合| 国产精品美女丝袜一区二区| 在线观看日产av网站| 欧美oldman色老头| 日韩av不卡电影在线观看| 人妻人人澡人人爽夜夜爽| 日本漂亮人妻熟妇| 亚洲欧美另类久久精品| 成人中文字幕乱码中文字幕| 久草在在线免视频在线观看| 国产精品久久久久久成人免费| 日韩欧美亚洲成人网| 人人妻人人爽久久久精品软件| 国家卫健委要求各地设黄码医院| 国产av一区二区青青草原| 欧美日韩亚洲精品视频| 日日爱亚洲一区av| 99热这里只有精品16| 日韩精品视频三级| 欧美日韩国产专区一区| 日韩熟妇中文字幕| 很黄很黄的在线上床| 久久综合九色综合欧洲98| 蜜桃臀久久久蜜桃臀| 亚洲中文字幕久久久av| 日本精品久久久久中文字幕2| 天天日天天干天天舔天天射| 中文字幕日产在线视频| 凹凸国产av熟女白浆| 成人在线视频免费国产 | 国产美女一区二区三区四区免费| 99蜜桃人妻免费在线看| 熟女义母乱码中文字幕| 中文字幕人妻丝袜二区在线69| 欧美激情日韩精品久久久| 日韩精品嘿咻视频| 中文日韩欧美第一页| 免费人成黄页网站大全在线观看| 色综合变态另类777| 精品国产一区二区三区av天堂 | 色婷婷 激情五月| 日本女人视频网站| 精品久久久久久一区二| 国产精品6久久久久久久| 日韩av一级大片| 91激情视频在线视频| 日韩欧美亚洲精品综合| 欧美日韩久久久久久久久| 久久99在线视频观看| 日韩三级电影大全中文字幕| 久草在在线免视频在线观看| 国产精品久久人人爽人人 | 五月婷婷大香蕉日韩| 午夜伊人狠狠av| 凹凸熟女白浆精品91| 日本在线丰满人妻| 国产精品久久久久久成人免费| 亚洲欧美日韩国产成人综合| 国内精品视频一区二区三| 亚洲少妇插b色图| 久久国产精品蜜臀免费| 麻豆www久久国产精品| 国产一区二区三区四区观看| 国产午夜精品在线免费观看| 欧美日韩特一级大片| 五月婷婷激情在线视频播放 | 久久婷婷色综合日韩一区一区| 亚洲男人天堂网在线看| 亚洲无人区乱码中文字幕一区| 999人妻熟妇一区二区三区精品| 午夜影院在线精品| 久久久久久99国产精品免费| 男人做受天堂青青操| 欧美精品久久久999| 国产综合精品久久东京热| 国产一区二区美女视频|