日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

firefly游戏服务器学习笔记 6———— db模块

發布時間:2024/3/12 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 firefly游戏服务器学习笔记 6———— db模块 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面介紹過master模塊,現在我們看看dbfront模塊,源碼在firefly/dbentrust和app/defront 目錄。

顧名思義 entrust 就是數據庫托管的意思。這個模塊實現的功能就是負責從數據庫讀取數據,并且緩存到memcache。然后定期的檢查緩存并寫入更新到DB。

?

剛剛看到9秒論壇里面有篇文章介紹這個dbentrust庫的左右。寫的很詳細。地址如下:

?? ????ht空格tp://www.9miao.com/thread-44002-1-1.html

既然文章已經寫了很詳細的說明,我就偷懶了:)

?

下面我主要介紹一下db整體模塊的結構,流程,邏輯。

前面的章節應該提到過,除了master模塊以外,其它模塊(db,gate,net,game1,admin)都是通過master的子進程方式啟動。啟動代碼如下:

?

??? defstartChildren(self):

??????? """

??????? """

??????? print "startchildren ......"

??????? config =json.load(open(self.configpath, 'r'))

??????? sersconf =config.get('servers')

??????? for sername insersconf.keys():

??????????? cmds = 'python%s %s %s' % (self.mainpath, sername, self.configpath)

??????????? subprocess.Popen(cmds,shell=True)

??????? reactor.run()

?

通過簡單加打印便可以發現,這里其實就是“python appmain.py db config.json”

?

OK,那么我們可以拋開master,單獨命令行啟動這個db模塊。

為了更加清晰的學習代碼,我已經把每個模塊單獨分離開,具體分離后的代碼請看github。 地址為:htt空格ps://github.com/chenee/firefly_study

?

我們下面自己那這份代碼解說,大家可以對照源代碼進行學習。

(說明,這份代碼只是為了學習才拆分開,會存在很多冗余,甚至不一致的地方。僅供參考)

代碼目錄如下:

1 .???????????????????????????????????????????????????????????????????????????????????????????????????????????????????

? 2 ├── app? #原先的游戲邏輯目錄,這個和firefly庫目錄對應,存放游戲具體實現。但是這里被我打亂了。

? 3 │?? ├── __init__.py

? 4 │?? ├── dbfront?#數據庫操作相關文件目錄

? 5 │?? │?? ├── McharacterManager.py #角色管理操作文件,從數據庫讀取所有角色信息,緩存到memcache

? 6 │?? │?? ├── __init__.py

? 7 │?? │?? ├── initconfig.py? #db模塊中游戲部分的初始化文件,負責app目錄的內容的加載。

? 8 │?? │?? ├── madminanager.py #MAdmin類的管理類。Madmin下面會提到。

? 9 │?? │?? ├── mcharacter.py #角色類,角色在memcache中的映射。

?10 │?? │?? └── memmode.py #幾個Madmin類的初始化工作

?11 │?? ├── dbfrontserver.py? #啟動接口,唯一作用就是調用initconfig.py

?12 │?? ├── logs

?13 │?? │?? └── dbfront.log #log文件

?14 │?? └── share

?15 │?????? ├──__init__.py

?16 │?????? └──dbopear?? #數據庫操作文件,對于db模塊來說就只使用了一個文件,typo!

?17 │??????????├── __init__.py

?18 │??????????└── dbCharacter.py #tb_character角色表的select,update封裝類。

?19 ├── appmain.py? #啟動腳本,讀config.json配置文件然后初始化DB模塊類

?20 ├── config.json? #配置文件,非常重要的文件

?21 ├── dbpool.py #db連接池,原先的文件只提供初始化和取連接池的2個函數。感覺很多dbopear目錄的的sql操作完全可以封裝,具體見我game1模塊里面的改動,其它幾個模塊的文件可能不同步。最終會按照game1的模式整合。

?22 ├── dbserver.py #db模塊的類文件,這個對于原先FFServer。針對每個模塊我把他改成對應名稱,便于理解

?23 ├── globalobject.py #全局類,這里的全局只每個模塊內部的全局,而不是整個系統的全局。每個模塊自己的globalobject類完全可以不同。

?24 ├── leafnode.py #就是原先的node.py,在PB那個章節我們介紹過。

?25 ├── logobj.py #log

?26 ├── memclient.py #memcache的客戶端實現,提供對memcache的訪問操作接口

?27 ├── memobject.py #memcached關系對象通過key鍵的名稱前綴來建立

各個key-value 直接的關系; 比如memobject.name= “tbl_role”, 那么memobject.get(“id”)得到的就是tbl_role:id的值。

?28 ├── mmode.py #里面包括2個重要的類,MMode,MAdmin;都是memobject的子類,邏輯上MMode代表內存中的一條數據,MAdmin,代表內存中的一張表。而前面madminanager.py就是這些表的管理類。

MAdmin對應memcache的前綴是表名稱:如tb_item

MMode對應memcache的前綴是pk(primary key,主鍵ID)。如 tb_item:1001

那么基本的一條數據組織的格式是:tbl_item:1001 {id:10001, name:chenee , money:10000};也就是memcache的key是 “ 表名稱:該條的主鍵值”,value是這條內容的json格式。

?

驗證方式,可以telnet到memcache打印出來看結果。(以前做的,現在記不清了,可能有誤,此刻我自己還木有驗證)

?

?29 ├── reference.py #PB相關,看前面一章介紹

30 ├── run.sh #shell啟動腳本,為了方便,我自己寫的。

?31 ├── serviceControl.py #對應原先的一個叫做admin.py的文件,其實就是給leafnode加2條命令(stop,reload)這個在PB章節也說過了。

?32 ├── services.py #服務類,前面提過

?33 ├── singleton.py #單例類,我blog上面有相關闡述,后面一章我粘貼過來。

?34 └── util.py #大部分都是sql查詢操作的封裝函數。

?35

?

?

仔細看完上面目錄介紹,基本上應該對DB的結構有個大致掌握了。下面我們分析一下源碼。

啟動db模塊的命令:

$cat run.sh

python appmain.py

appmain.py便于學習被我改動過了,如下:

if __name__ == "__main__":

??? servername ="dbfront"

??? config =json.load(open("config.json", 'r'))

?

??? dbconf =config.get('db')

??? memconf =config.get('memcached')

??? sersconf =config.get('servers',{})

??? masterconf = config.get('master',{})

??? serconfig =sersconf.get(servername)

?

??? ser = DBServer()

??? ser.config(serconfig,dbconfig=dbconf, memconfig=memconf,masterconf=masterconf)

??? ser.start()

?

實際上就是實例化DBServer類,把從config.json文件讀取的信息傳遞過去。DBServer就是原先firefly/server/server.py文件。改個名字好看。

config.json也被我改了一下,“services”里面只保留“dbfront”,其它都services內容都無關。就不貼出來了,占地方。

?

現在看DBServer(FFServer)類:

class DBServer:

?

??? def __init__(self):

??????? """

??????? """

??????? self.leafNode =None

??????? self.db = None

? ??????self.mem = None

??????? self.servername =None

?

??? defconfig(self,config,dbconfig = None,memconfig = None,masterconf=None):

??????? """配置服務器

??????? """

??????? servername =config.get('name')#服務器名稱

??????? logpath =config.get('log')#日志

??????? hasdb =config.get('db')#數據庫連接

??????? hasmem =config.get('mem')#memcached連接

?

??????? app =config.get('app')#入口模塊名稱

?

??????? self.servername =servername

?

??????? if masterconf:

??????????? masterport =masterconf.get('rootport')

??????????? addr = ('localhost',masterport)

??????????? self.leafNode= leafNode(servername)

???????????self.leafNode.connect(addr)

???????????GlobalObject().leafNode = self.leafNode

?

?

??????? if hasdb anddbconfig:

???????????log.msg(str(dbconfig))

???????????dbpool.initPool(**dbconfig)

?

??????? if hasmem andmemconfig:

??????????? urls =memconfig.get('urls')

??????????? hostname =str(memconfig.get('hostname'))

???????????mclient.connect(urls, hostname)

?

??????? if logpath:

???????????log.addObserver(loogoo(logpath))#日志處理

???????log.startLogging(sys.stdout)

?

?

??????? if app:

???????????reactor.callLater(0.1,__import__,app)

?

?

??? def start(self):

??????? """啟動服務器

??????? """

??????? log.msg('%sstart...'%self.servername)

??????? log.msg('%s pid:%s'%(self.servername,os.getpid()))

??????? reactor.run()

?

?

根據config.json的解析結果,我們精簡掉所有無關內容。發現,DB模塊包括以下幾個功能模塊:

mastconfig #說明我們需要連接一個root,也就是前面提到的master模塊

db #有數據庫操作,需要簡歷數據池

mem #有memcache操作,要連接memcache。

?

所有連接信息,如ip、port等都是從config.json里面取得。

1、masterconfig部分,就是前面PB章節的介紹,這里實現leafNode去連接master模塊的root,就不再贅述了。

2、db pool部分也很簡單,就是建立一個pool,提供一個connection的接口。大家去了解DBUtils.PooledDB這個庫就可以了。

3、mem部分,也沒有啥可說,純memclient就是調用python的Memcache而已,memcache的結構又超級簡單,就是get,set。不含任何邏輯的。想要實現邏輯關系,都要自己去構建,就是上面我們提到的MMode和MAdmin等文件來實現。

?

OK,firefly庫部分的調用完畢,這個時候DB模塊已經建立了,和master的PB連接,數據池,memcache連接。下面就是游戲內容部分的實現了。

?

除了master模塊,其它所有模塊的游戲部分(app目錄下面的內容)都是通過

??????? if app:

???????????reactor.callLater(0.1,__import__,app)

這種方式來import進來的。對我這種python新手還真的迷惑的半天。實際上就是根據config.json里面對于app項的內容。對于db這里展開是:

?? reactor.callLater(0.1,__import__,app.dbfrontserver)

就是過0.1秒執行 import app.dbfrontserver。其內容如下:

GlobalObject().stophandler = initconfig.doWhenStop

initconfig.loadModule()

loadModule()干3件事情:

def loadModule():

??? register_madmin()

??? initData()

??? CheckMemDB(1800)

注冊幾個表,初始化角色數據到內存,同步內存數據到數據庫

?

注冊表的代碼在mmode.py中,過程就是實例化幾個MAdmin來表示相應表的結構,然后添加到MAdminManager這個單例管理類中。

MAdmin有幾個屬性代表表的主鍵,外鍵,表名稱等信息。

MAdmin的insert函數會調用父類的Memobject的insert函數。

??????? nowdict =dict(self.__dict__)

??????? delnowdict['_client']

??????? newmapping =dict(zip([self.produceKey(keyname) for keyname in nowdict.keys()],

?????????????????????????????nowdict.values()))

???????self._client.set_multi(newmapping)

實際上就是根據self的所有屬性(除了_client,這個屬性指的是memclient)來生成一個字典,然后把這個字典的內容緩存到memcache中。

比如tb_item表對應的MAdmin,生成的memcache內容就包括(不限于)

Key?????????????????????value

tb_item:_name????? xxxx

tb_item:_lock????? xxxx

tb_item:_fk????? xxxx

tb_item:_pk??? xxxxx

這里其實只是把表結構給緩存到memcache了,壓根沒有碰表的數據。MAdmin有幾個個函數可以取數據,

load()#這個是根據表名稱,select * 并且一條一條生成MMode,然后緩存進memcache,MMode前面提到過,代表一條數據的內存對應數據結構。

?

getObj(self,pk):#先判斷pk這條數據是否在memcache,是否有效,如果沒有再從數據庫取出來并同步到memcache中。

?

這兩條函數其實在db模塊啟動過程中都沒有被調用,(可以加斷點或者打印驗證)

?

OK,分析到這里下面在看角色初始化initData()的部分就簡單了

?? def initData(self):

??????? allmcharacter =dbCharacter.getALlCharacterBaseInfo()

??????? for cinfo inallmcharacter:

??????????? pid =cinfo['id']

??????????? mcha =Mcharacter(pid, 'character%d' % pid, mclient)

???????????mcha.initData(cinfo)

Mcharacter也是MemObject的子類,做的就是根據數據庫中的角色信息實例化Mcharacter內存數據,然后調用memobject的insert同步到memcache。

取角色信息的過程相反。調用mcharacterinfo()函數,唯一一點不同是,這個函數有@property修飾,我查了一下,表示這個函數可以當成屬性來用,python真酷!

?

?

這里吐槽一下注釋: 擺明是從啥地方copy過來的,注釋的牛頭不對馬嘴,害的我看了老半天,都木有想明白。

"""初始化城鎮要塞對象

??????? @paramterritoryId: int 領地的ID

??????? @param guard:int 殖民者的ID

??????? @paramguardname: str 殖民者的名稱

??????? @paramupdateTime: int 領地被更新的時間

"""

最后再嘮叨一下checkAdmins();這個函數負責每隔1800(magic number)秒刷一邊MAdminManager類管理的所有MAdmin(表)。調用這些MAdmin對應的checkAll();

這個checkAll函數會取得memcache中所有緩存數據,比較是否以本表前綴開頭,如果是,則判斷這些是否有效,是否過期,是否需要寫入數據庫。。。。

?

在我看來,這里有些可以優化的邏輯。比如把取memcache所有數據的步驟提到MAdminManager層面,這樣每個MAdmin就不用單獨執行一遍。

但是如果是多個memcache服務器,又該怎么辦?各種頭疼,問題太多,智商不夠用。

?

這個函數是魔鬼,我暫時沒有敢去動它,等我多學習學習相關內容再去做優化。

總結

以上是生活随笔為你收集整理的firefly游戏服务器学习笔记 6———— db模块的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。