• <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>

            ACG狂人

            其實(shí)我更愛姐汁...

            #

            封裝MySQL時(shí)解決的兩個(gè)字符集問題

            在我開始封裝MySQL C API時(shí),真的沒有想過居然會(huì)在字符集問題上連續(xù)卡殼,折騰了一下午+一晚上,終于搞定這些問題。下面記錄一下我遇見的問題以及解決辦法,以作備忘。
            首先遇見的當(dāng)然是中文亂碼問題。這個(gè)問題相對(duì)來說資料比較多,文檔寫得應(yīng)該也是很清楚的,但是我沒心思看,靠猜搞定。我首先設(shè)置MySQL服務(wù)器的默認(rèn)字符集為UTF8,并保證我操作的表中的列字符集也是UTF8,然后重啟MySQL服務(wù),并嘗試用mysql_query("INSERT INTO TestTable VALUES('你好')")來寫入,結(jié)果失敗在預(yù)料之中。我猜可能可以使用類似"INSERT INTO TestTable VALUES('\0x2734\0x3432')"這樣的方式寫入中文,但這樣太丑了,也沒有實(shí)用價(jià)值,我堅(jiān)決不會(huì)去用。我又嘗試使用MultiByteToWideChar去做,甚至使用了Qt的QTextCodec去轉(zhuǎn)換“你好”這兩個(gè)字,結(jié)果依然失敗。這就有些蹊蹺了,我決定調(diào)用mysql_character_set_name()看看到底有沒有正確的設(shè)置成UTF8格式,讓我意料之外的是:結(jié)果是latin1,這難道是拉丁字符集??我查看了一下API函數(shù)的相關(guān)說明,發(fā)現(xiàn)這里獲取到的是客戶端鏈接的字符集,我突然覺得,也許MySQL可以自動(dòng)的在客戶端與服務(wù)器之間的字符集進(jìn)行轉(zhuǎn)化!說做就做,我查到了可以用mysql_options()或者mysql_set_character_name()函數(shù)來設(shè)置客戶端鏈接字符集,但這兩個(gè)函數(shù)用的時(shí)機(jī)分別在調(diào)用mysql_real_connect()之前或之后。我將客戶端鏈接設(shè)置成gb2312字符集,這是VC中支持中文的標(biāo)準(zhǔn)字符集之一(另一個(gè)標(biāo)準(zhǔn)是UTF16,需要用wchar_t  wstring和常量字符串前的L),結(jié)果,當(dāng)然是非常正確的插入中文啦,呵呵!
            正當(dāng)我覺得下面的封裝肯定會(huì)順湯順?biāo)畷r(shí),在封裝基本完成的時(shí)候,我發(fā)現(xiàn)控制臺(tái)不能輸出我從MySQL取出的中文了!這太奇怪了,輸出英文就沒有問題,而中文雖然的確被準(zhǔn)確無誤的讀入了std::string中(通過單步調(diào)試和ofstream得到確認(rèn)),然而輸出到cout中卻會(huì)出錯(cuò)。為什么文件流沒問題,控制臺(tái)流會(huì)出問題呢?我跟蹤了代碼,發(fā)現(xiàn)在fputc()函數(shù)中出現(xiàn)了問題。另一個(gè)奇特的地方,就是在mysql_init()函數(shù)被調(diào)用之前,cout可以正確輸出中文,但調(diào)用之后就不能輸出,iostate被賦予4值,即badbit。我求了一下google,發(fā)現(xiàn)sputc()中的一個(gè)_nolock_write()函數(shù)是msvcrtd.lib中的函數(shù),暈了,我在單步調(diào)試中也發(fā)現(xiàn)就是這里有問題,確切的說,mysql_init()函數(shù)被調(diào)用后,_nolock_write()函數(shù)就會(huì)出錯(cuò)。哈哈,總結(jié)出了這些特點(diǎn)之后,我已經(jīng)隱約猜到了是哪里的問題了,還記得前幾日才寫的blog里的東西,我由于想要將libmysql.lib換成mysqlclient.lib靜態(tài)庫(kù),所以便禁掉了msvcrtd.lib庫(kù),我肯定這里面有關(guān)聯(lián)。
            到底是什么原因呢?我覺得,由于這個(gè)MySQL的SDK不是我自己編譯的,mysqlclient.lib里面調(diào)用crt函數(shù)時(shí),對(duì)字符集的本地化做了設(shè)置,由于是歐美的字符集設(shè)置,所以一旦我調(diào)用了mysqlclient.lib里的函數(shù),就無法再顯示中文了。
            猜出了問題的根源,那么如何解決這個(gè)問題呢?我可以肯定的是,使用std::cout.imbue(std::locale())是行不通的,那么下面就是列出的幾個(gè)辦法:
            1、使用人家編譯好的動(dòng)態(tài)庫(kù),libmysql.lib,并將libmysql.dll拷貝過來,由于動(dòng)態(tài)庫(kù)和你的程序共享crt dll,因此字符集設(shè)置應(yīng)該會(huì)是一致的。
            2、如果你還是想用靜態(tài)庫(kù),可以考慮自己下載源碼并編譯一遍,這是根本的解決辦法。
            3、如果你可以自己編譯,且想用mysqlclient.lib,那么就重新編譯mysqlclient吧,動(dòng)態(tài)靜態(tài)都可以。不過官網(wǎng)上下載的編譯好的mysqlclient.lib是靜態(tài)的,不能使用。

            我最終的解決辦法是第1種,因?yàn)楸容^懶,不想自己再去編譯了,呵呵。

            posted @ 2009-10-09 22:29 釀妹汁 閱讀(1963) | 評(píng)論 (3)編輯 收藏

            原來靜態(tài)庫(kù)是這樣鏈接的

            最近在win32平臺(tái)下封裝MySQL的客戶端C API時(shí),出現(xiàn)的問題著實(shí)讓我頭痛了個(gè)把小時(shí),不過多虧這一來,我終于明白了靜態(tài)庫(kù)是怎樣鏈接的,結(jié)合了以前我對(duì)動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)之間進(jìn)行比較的一些測(cè)試結(jié)論,也明白了為什么靜態(tài)庫(kù)需要這樣的設(shè)計(jì)。不由感嘆一下古人的那句話:“挫折果真是成功的母親。”(好大霧^_^!)
            閑話不多說,記錄一些關(guān)鍵點(diǎn),首先是靜態(tài)鏈接到底和動(dòng)態(tài)鏈接有哪些不太容易發(fā)現(xiàn)的區(qū)別呢?我來假設(shè)libA依賴libB,那么我的執(zhí)行文件在使用libA的時(shí)候也需要導(dǎo)入libB才能正確鏈接,但若dllA依賴libB的話,則只需導(dǎo)入dllA就可以。我在一開始用MySQL時(shí)使用的內(nèi)嵌數(shù)據(jù)庫(kù)模式,所以導(dǎo)入的是那個(gè)libmysql.dll動(dòng)態(tài)庫(kù),因此沒出現(xiàn)問題。而換上了mysqlclient.lib后,居然告訴我沒有找到socket相關(guān)的實(shí)現(xiàn),即“無法解析的外部符號(hào)”這類錯(cuò)誤,于是乎我只有加上ws2_32.lib庫(kù)才能通過。
            為什么這樣設(shè)計(jì)?原因其實(shí)跟靜態(tài)庫(kù)的連接方式有關(guān),由于靜態(tài)庫(kù)直接將函數(shù)實(shí)現(xiàn)和全局靜態(tài)變量導(dǎo)入到包含它的執(zhí)行體中,所以在多層多重的庫(kù)包含中就會(huì)有大量重定義的問題存在,想想你在一個(gè)靜態(tài)庫(kù)中用了單件模式,那么其他庫(kù)又包含你這個(gè)庫(kù),最后exe又包含所有這些庫(kù),最終形成菱形依賴,如果靜態(tài)庫(kù)不這樣設(shè)計(jì)的話,問題就會(huì)像C++的多重繼承問題一樣。之所以靜態(tài)庫(kù)這樣設(shè)計(jì),跟C++的虛擬繼承思想簡(jiǎn)直如出一轍。(我知道這段話其實(shí)只有已經(jīng)懂了的人才能看得懂,不過沒辦法,我表達(dá)能力挺笨的...)

            還有個(gè)極度郁悶的地方是:mysqlclient.lib中的libcmtd.lib和msvcrtd.lib這對(duì)活寶居然也被鏈接進(jìn)去了,我這邊首先需要忽略這兩個(gè)默認(rèn)庫(kù),然后再包含msvcrtd.lib才可以。我不知道為啥sdk提供的靜態(tài)庫(kù)非得在c runtime link的方式上跟一般人過不去,又懶得去自己編譯,哎!將就一下就這么用吧......

            posted @ 2009-10-06 21:30 釀妹汁 閱讀(1580) | 評(píng)論 (0)編輯 收藏

            PhysX動(dòng)工

            PhysX物理引擎是眾多可選的物理引擎之一,但為什么我要選PhysX而不是其他呢?也許下面的一些論述純粹是自己的意淫,因?yàn)椴]有真正的去測(cè)試過這些,不對(duì)之處請(qǐng)看官們指點(diǎn)一二,免讓我這個(gè)糊涂蟲誤入歧途。

            選擇PhysX的原因是這樣的,拿目前與PhysX對(duì)立的Havok引擎來做比較,Intel和AMD-ATI支持的Havok引擎主要致力于CPU運(yùn)算物理效果,而nvidia獨(dú)推的cuda架構(gòu)和PhysX引擎則主要致力于GPU或GPU群集運(yùn)算,且不談在游戲客戶端的物理效果到底是用GPU好還是CPU好(這跟你GPU是否忙得過來有關(guān)),由于目前正在攻關(guān)的游戲開發(fā)項(xiàng)目需求較為特殊,我在這里只關(guān)注服務(wù)器方面的高性能剛體物理運(yùn)算問題。nvidia近兩年推出的cuda架構(gòu)群集不斷走向成熟,這種群集是用GPU陣列作為運(yùn)算核心的超級(jí)并行計(jì)算機(jī),在物理運(yùn)算方面與CPU所組成的群集不是一個(gè)檔次,總體運(yùn)算性能甚至超過同等價(jià)位的CPU群集近百倍!我考慮將物理運(yùn)算完全交給獨(dú)立的GPU群集,讓CPU去做那些它所擅長(zhǎng)的工作。也許這正是符合了nvidia推廣cuda的思想吧,因此看著PhysX對(duì)我就有格外的吸引力,所以當(dāng)然是奮力研究了。

            于是去了nvidia官網(wǎng)的Download區(qū),先搞下來三個(gè)東西:cuda sdk、cuda toolkit、cuda 那個(gè)啥??沒啥,只是隨便看看,順帶裝了下cuda顯卡驅(qū)動(dòng),呵呵。于是又下了PhysX的SDK,好了,等一切安裝完畢,設(shè)置好包含目錄和庫(kù)目錄后就開始了我的HelloWorld歷程!寫一個(gè)PhysX的HelloWorld較為麻煩,要有能看得見的效果還得累一陣子,于是直接拿sample里的教程進(jìn)行修改,第一步當(dāng)然是戳一戳剛體碰撞了,發(fā)現(xiàn)PhysX的抽象建模比我料想的好很多,基本上我所考慮到的它全有了,而且理解起來非常簡(jiǎn)單。

            PhysX的建立過程只有很少量的代碼,首先是建立一個(gè)SDK對(duì)象,然后建立碰撞場(chǎng)景NxScene。
            在PhysX中,一個(gè)可以檢測(cè)碰撞的對(duì)象叫做NxActor,這個(gè)NxActor的建立除了需要一個(gè)指定的NxScene以外,還需要一些描述信息,這些描述如下:
            碰撞對(duì)象的外形描述: 統(tǒng)一用的是NxXXXShapeDesc的命名方式,譬如NxBoxShapeDesc,甚至NxTranglesMeshShapeDesc之類的,你可以將任意的3D形態(tài)做成NxActor的外形,物理引擎會(huì)根據(jù)這個(gè)外形的面來做碰撞檢測(cè)和質(zhì)點(diǎn)的根據(jù)。
            碰撞對(duì)象的體型描述: 即NxBodyDesc,用于記錄一個(gè)碰撞對(duì)象的質(zhì)量、初始速度、初始沖量等信息,感覺似乎是將一個(gè)對(duì)象作為一個(gè)質(zhì)點(diǎn)考慮時(shí)的一些數(shù)據(jù),總之,沒有這個(gè)描述的話,碰撞對(duì)象會(huì)被視為一個(gè)靜態(tài)對(duì)象,即不能主動(dòng)變動(dòng)坐標(biāo)的物體,亦不會(huì)存在質(zhì)量和速度等信息。
            材質(zhì)ID:材質(zhì)是在物理引擎的NxScene中建立的,每個(gè)對(duì)象所使用的材質(zhì)ID都是指的是NxScene中的第幾個(gè)材質(zhì)。材質(zhì)包括了摩擦力和彈力之類的信息。

            恩,目前還沒看到j(luò)oint的使用,估計(jì)就是連接兩個(gè)碰撞對(duì)象的一種力學(xué)關(guān)系吧,來回?cái)[動(dòng)的吊籃,上面又要能站人,肯定需要這個(gè)。這樣看來,剛體基本上不存在什么問題了,而在我目前攻關(guān)的服務(wù)器部分,只需要?jiǎng)傮w部分,因此PhysX的學(xué)習(xí)目前到此為止了,接下來就是對(duì)游戲服務(wù)器的框架設(shè)計(jì)上多下功夫了。

            posted @ 2009-09-03 01:28 釀妹汁 閱讀(1927) | 評(píng)論 (2)編輯 收藏

            異常處理的可惡陷阱

            也許這個(gè)錯(cuò)誤是很幼稚的,但是他著實(shí)難住了我好幾個(gè)小時(shí),一度我還以為永遠(yuǎn)解不開這個(gè)謎題了(*o*),情況是這樣的,異常在拋出之后,到達(dá)處理異常的catch域,但這時(shí)上下文必須依然有效才行,否則catch將接收不到拋出的異常。具體代碼如下:
                try
                
            {
                    moeutil::simple_pool spool(
            32);
                    
            void* p1 = spool.malloc(15);
                    
            void* p2 = spool.malloc(102);
                    
            void* p3 = spool.malloc(154);
                    
            void* p4 = spool.malloc(7);
                    
            void* p5 = spool.malloc(7);
                    
            void* p6 = spool.malloc(70);
                    
            //std::cout<<p1<<'\n'<<p2<<'\n'<<p3<<'\n'<<p4<<'\n'<<p5<<'\n'<<p6<<std::endl;
                    spool.free(p1);
                    spool.free(reinterpret_cast
            <char*>(p2)+2);
                    spool.free(p3);
                    spool.free(p4);
                    spool.free(p5);
                    spool.free(p6);

                }
            catch (moeutil::Exception& e){
                    std::cout
            <<e.what()<<std::endl;
                }
            這是一個(gè)簡(jiǎn)易的內(nèi)存池類,其中simple_pool的析構(gòu)函數(shù)會(huì)拋出異常,然后free函數(shù)也會(huì)拋出異常。析構(gòu)函數(shù)可以檢測(cè)是否有內(nèi)存泄漏,而free函數(shù)是檢測(cè)到無效的傳入指針時(shí)會(huì)拋出異常。析構(gòu)拋出異常是沒問題的,但是free拋出異常的時(shí)候問題就來了,當(dāng)free拋出異常時(shí),由于會(huì)脫離try塊,所以spool也會(huì)被析構(gòu),這樣就會(huì)陷入麻煩,由于沒有全部free,所以析構(gòu)本身也會(huì)拋出異常,導(dǎo)致了類似于異常迭代的情況。也就是說,在throw一個(gè)異常的過程中又一次觸發(fā)了異常。于是windows系統(tǒng)的debug error對(duì)話框出現(xiàn)了,而且是出現(xiàn)在throw那一行。
            此隨筆用于提醒自己勿犯第二次!

            posted @ 2009-08-02 17:12 釀妹汁 閱讀(670) | 評(píng)論 (1)編輯 收藏

            使用boost庫(kù)需要一定的素質(zhì)

                    可能由于在幾個(gè)博客上發(fā)布了一些boost庫(kù)使用心得的關(guān)系,最近總是被一些相關(guān)的詢問郵件騷擾,而提問者問的問題卻又讓我不知道如何回答才好,或者說根本沒有辦法回答。一些問題根本就不該問的,所以便發(fā)些感慨,還望看了本人一些心得又不禁想問一些偷懶問題的各位手下留情,不要再問我一些奇怪的問題了(*w*)!
                    我們學(xué)習(xí)并使用boost庫(kù)的目的是簡(jiǎn)化編程,這并不代表簡(jiǎn)化到你根本不需要去理解原理的地步。我想,如果您希望很好的駕馭boost庫(kù)的話,那么請(qǐng)對(duì)您自己發(fā)發(fā)狠努力編寫代碼積累經(jīng)驗(yàn),直到您認(rèn)為boost庫(kù)中30%的功能您都能夠親自動(dòng)手實(shí)現(xiàn)的時(shí)候,才嘗試去使用它。類似“怎么讓線程組和asio合作使用”之類的問題,我覺得很囧,而且問的人還非常多,給代碼都還迷糊。我覺得您想用asio,請(qǐng)先嘗試編寫線程類和IOCP框架的應(yīng)用程序,如果您連線程類都寫不好,或者連一個(gè)多線程死鎖和共享區(qū)都不能安全排除的話,請(qǐng)先打打基礎(chǔ)吧。
                    boost庫(kù)是一個(gè)非常有深度的東西,也是智慧的結(jié)晶,有很多東西在一定條件下您可以不用深究,但是起碼的30%則必須刨根問底,這30%實(shí)際上都是很基礎(chǔ)的東西,切不可急于一時(shí)而至整個(gè)工程最終因?yàn)閎oost的一點(diǎn)小問題卡殼,倘若無法駕馭,則不如不用,再急我也沒法幫您了!

            posted @ 2009-07-30 18:19 釀妹汁 閱讀(18974) | 評(píng)論 (26)編輯 收藏

            VC編譯器中的一些編譯時(shí)命令備忘

             

            // 加載靜態(tài)庫(kù)
            #pragma comment(lib, "路徑+LIB庫(kù)名")

            // 禁止1221號(hào)警告
            #pragma warning(disable: 1221)

            // 導(dǎo)入并加載DLL exe之類的二進(jìn)制動(dòng)態(tài)庫(kù)
            #import "路徑+二進(jìn)制庫(kù)名"

            // 將ClassName類中的s_Data靜態(tài)成員變量定義在頭文件中時(shí)防止重定義
            __declspec(selectany) int ClassName::s_Data = 0;

            // 當(dāng)用戶使用void func()函數(shù)時(shí),編譯器將作出警告,并顯示“不推薦使用該函數(shù)”字樣
            __declspec(deprecated("不推薦使用該函數(shù)")) void func();

            posted @ 2009-07-30 18:00 釀妹汁 閱讀(959) | 評(píng)論 (0)編輯 收藏

            記錄一下C++標(biāo)準(zhǔn)流感悟

                    今天終于完成了自己的日志庫(kù)核心的幾個(gè)類和算法,折騰了許久,感覺安全性很好,一些多線程的死鎖問題已經(jīng)逐個(gè)排除了。由于需要跟C++標(biāo)準(zhǔn)庫(kù)的輸入輸出流共事,所以么總算自認(rèn)為理解了C++標(biāo)準(zhǔn)流的一些特性,記下來以供備忘。
                    首先是文件流,關(guān)于該流的問題,要扯就扯遠(yuǎn)了,主要說一說std::wofstream的問題。不要被這個(gè)w騙了,其實(shí)它輸出到文件上的依然還是那么回事,沒有絲毫的變化。如果你是想輸出Unicode到文本文件中,那么你最好是用ios::binary模式,然后一股腦的倒入文件中,如果要是使用<<重載符號(hào)的話,輸出到文件中的跟std::ofstream沒區(qū)別,而且中文還無法輸出。如果你遇見中文無法輸出的問題,恩,可以調(diào)用std::wofstream::imbue()方法,具體也就是一行:ofs.imbue(std::locale("chs"));搞定。
            我想,C++標(biāo)準(zhǔn)庫(kù)并不支持Unicode編碼,而是給字符地域化的編碼方式,中文的可能也就是GBK吧,聽說C++0x標(biāo)準(zhǔn)會(huì)納入U(xiǎn)nicode編碼支持,如果是這樣的話就省心多了。
                    然后還有個(gè)不省心的地方就是流的streambuf中的緩沖大小了,我發(fā)現(xiàn),fstream中的寫緩沖居然一直是0啊,這個(gè)就很頭疼了,需要給文件流指定緩沖的大小。

            posted @ 2009-07-29 23:46 釀妹汁 閱讀(1025) | 評(píng)論 (2)編輯 收藏

            DLL的共享測(cè)試

            今天稍微實(shí)驗(yàn)了一下DLL的數(shù)據(jù)共享問題,做了兩種情況下的測(cè)試,第一種是兩個(gè)進(jìn)程同時(shí)調(diào)用一個(gè)DLL的實(shí)驗(yàn),另一種是一個(gè)進(jìn)程調(diào)用一個(gè)兩個(gè)DLL,然后這兩個(gè)DLL有依賴關(guān)系,記錄一下得到的測(cè)試結(jié)果。

            當(dāng)一個(gè)進(jìn)程調(diào)用LoadLibrary、LoadLibraryEx以及FreeLibrary時(shí),DllMain會(huì)被調(diào)用,從DllMain的入口函數(shù)的第二個(gè)參數(shù)可以得知是加載還是釋放。LoadLibraryEx的flag參數(shù)傳入DONT_RESOLVE_DLL_REFERENCES可以跳過DllMain的調(diào)用,這在很多時(shí)候是有用的。
            當(dāng)一個(gè)進(jìn)程在調(diào)用LoadLibrary后又啟動(dòng)了線程,則每啟動(dòng)一個(gè)線程,就會(huì)調(diào)用一次DllMain,同樣可以從DllMain的第二個(gè)參數(shù)的值來區(qū)分調(diào)用時(shí)由進(jìn)程引起的還是由線程引起的。第二個(gè)參數(shù)的值一般有4種,如下:
             DLL_PROCESS_ATTACH
             DLL_PROCESS_DETACH
             DLL_THREAD_ATTACH
             DLL_THREAD_DETACH
            不用解釋也能看得出來分別是表示什么意義了,通過這個(gè)可以選擇性的對(duì)DLL中的數(shù)據(jù)進(jìn)行初始化。
            如果是兩個(gè)進(jìn)程同時(shí)調(diào)用一個(gè)DLL的話,數(shù)據(jù)是不會(huì)共享的,除非你設(shè)置了seg項(xiàng)為共享,具體不同的編譯器會(huì)有不同的設(shè)置方法。兩個(gè)進(jìn)程對(duì)同一個(gè)DLL的調(diào)用計(jì)數(shù)也是分開的,這讓我很放心了,之前一直害怕的沖突問題釋然。


            當(dāng)一個(gè)進(jìn)程去調(diào)用一個(gè)DLL甲,而甲又在初始化的時(shí)候調(diào)用了DLL乙,進(jìn)程通過甲的函數(shù)來訪問了DLL乙,同時(shí)自己也親自調(diào)用了DLL乙并取出和更改了數(shù)據(jù)。這樣的情況下,DLL乙的引用計(jì)數(shù)是共享的,數(shù)據(jù)也是共享的,加載和釋放都很安全,之前擔(dān)心DLL乙中的單件會(huì)被重復(fù)調(diào)用的情況也不可能存在了。

            posted @ 2009-06-27 23:04 釀妹汁 閱讀(569) | 評(píng)論 (0)編輯 收藏

            ASIO攻破!!!

            花了足足3天時(shí)間,外加1天心情休整,終于在第5天編寫出了一個(gè)能運(yùn)行的基于asio和thread_group的框架,差點(diǎn)沒氣暈過去,把源碼都看懂了才感覺會(huì)用了。
            測(cè)試了一下,debug下一萬次回應(yīng)耗時(shí)800+毫秒,release下是200+毫秒,機(jī)器配置雙核2.5G英特爾,4個(gè)線程并行工作,無錯(cuò)的感覺真好,再也不用擔(dān)心iocp出一些奇怪的問題啦,因?yàn)槭蔷奕藗儗懙膶?shí)現(xiàn),呵呵。

            進(jìn)入正題,簡(jiǎn)要說一下asio的實(shí)現(xiàn)原理吧。在win32平臺(tái)上,asio是基于IOCP技術(shù)實(shí)現(xiàn)的,我以前也用過IOCP,卻沒想到居然能擴(kuò)展成這樣,真是神奇!在其他平臺(tái)下還會(huì)有別的方法去實(shí)現(xiàn),具體見io_service類下面這部分的源碼:
              // The type of the platform-specific implementation.
            #if defined(BOOST_ASIO_HAS_IOCP)
              typedef detail::win_iocp_io_service impl_type;
              friend 
            class detail::win_iocp_overlapped_ptr;
            #elif defined(BOOST_ASIO_HAS_EPOLL)
              typedef detail::task_io_service
            <detail::epoll_reactor<false> > impl_type;
            #elif defined(BOOST_ASIO_HAS_KQUEUE)
              typedef detail::task_io_service
            <detail::kqueue_reactor<false> > impl_type;
            #elif defined(BOOST_ASIO_HAS_DEV_POLL)
              typedef detail::task_io_service
            <detail::dev_poll_reactor<false> > impl_type;
            #else
              typedef detail::task_io_service
            <detail::select_reactor<false> > impl_type;
            #endif
            這部分代碼其實(shí)就在boost::asio::io_service類聲明中的最前面幾行,可以看見在不同平臺(tái)下,io_service類的實(shí)現(xiàn)將會(huì)不同。很顯然,windows平臺(tái)下當(dāng)然是win_iocp_io_service類為實(shí)現(xiàn)了(不過我一開始還以為win_iocp_io_service是直接拿出來用的呢,還在疑惑這樣怎么有移植性呢?官方文檔也對(duì)該類只字不提,其實(shí)我卡殼就是卡在這里了,差點(diǎn)就直接用這個(gè)類了^_^!)。

            那么就分析一下win_iocp_io_service的代碼吧,這里完全是用IOCP來路由各種任務(wù),大家使用post來委托任務(wù),內(nèi)部調(diào)用的其實(shí)是IOCP的PostQueuedCompletionStatus函數(shù),然后線程們用run來接受任務(wù),內(nèi)部其實(shí)是阻塞在IOCP的GetQueuedCompletionStatus函數(shù)上,一旦有了任務(wù)就立即返回,執(zhí)行完后再一個(gè)循環(huán),繼續(xù)阻塞在這里等待下一個(gè)任務(wù)的到來,這種設(shè)計(jì)思想堪稱神奇,對(duì)線程、服務(wù)以及任務(wù)完全解耦,靈活度達(dá)到了如此高度,不愧為boost庫(kù)的東西!我只能有拜的份了...

            說一下總體的設(shè)計(jì)思想,其實(shí)io_service就像是勞工中介所,而一個(gè)線程就是一個(gè)勞工,而調(diào)用post的模塊相當(dāng)于富人們,他們?nèi)ブ薪樗腥蝿?wù),而勞工們就聽候中介所的調(diào)遣去執(zhí)行這些任務(wù),任務(wù)的內(nèi)容就寫在富人們給你的handler上,也就是函數(shù)指針,指針指向具體實(shí)現(xiàn)就是任務(wù)的實(shí)質(zhì)內(nèi)容。其實(shí)在整個(gè)過程中,富人們都不知道是哪個(gè)勞工幫他們做的工作,只知道是中介所負(fù)責(zé)完成這些就可以了。這使得邏輯上的耦合降到了最低。不過這樣的比喻也有個(gè)不恰當(dāng)?shù)牡胤剑绻惨@樣比喻的話,我只能說:其實(shí)勞工里面也有很多富人的^o^! 。很多勞工在完成任務(wù)的過程中自己也托給中介所一些任務(wù),然后這些任務(wù)很可能還是自己去完成。這也難怪,運(yùn)行代碼的總是這些線程,那么調(diào)用post的肯定也會(huì)有這些線程了,不過不管怎么說,如此循環(huán)往復(fù)可以解決問題就行,比喻不見得就得恰當(dāng),任何事物之間都不可能完全相同,只要能闡述思想就行。

            最后還要說明的一點(diǎn)就是:委托的任務(wù)其實(shí)可以設(shè)定執(zhí)行的時(shí)間的,很不錯(cuò)的設(shè)定,內(nèi)部實(shí)現(xiàn)則是通過定時(shí)器原理,GetQueuedCompletionStatus有一個(gè)等待時(shí)間的參數(shù)似乎被用在這方面,還有源碼中的定時(shí)器線程我并沒有過多的去理解,總之大體原理已基本掌握,剩下的就是使勁的用它了!!!

            另外為了方便人交流,在這里插入一些代碼可能更容易讓人理解吧,
            下面這個(gè)是啟動(dòng)服務(wù)時(shí)的代碼:
            void ServerFramework::run()
            {
                boost::thread_group workers;
                
            for (uint32 i = 0; i < mWorkerCount; ++i)
                    workers.create_thread(
                        boost::bind(
            &boost::asio::io_service::run, &mIoService));
                workers.join_all();
            }

            在打開前就得分配好任務(wù),否則線程們運(yùn)行起來就退出了,阻塞不住,任務(wù)的分配就交給open函數(shù)了,它是分配了監(jiān)聽端口的任務(wù),一旦有了連接就會(huì)拋出一個(gè)任務(wù),其中一個(gè)線程就會(huì)開始行動(dòng)啦。
            void ServerFramework::open(const String& address, const String& port, uint32 nWorkers /*= DEFAULT_WORKER_COUNT*/)
            {
                
            // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
                boost::asio::ip::tcp::resolver resolver(mIoService);
                boost::asio::ip::tcp::resolver::query query(address, port);
                boost::asio::ip::tcp::endpoint endpoint 
            = *resolver.resolve(query);

                mAcceptor.open(endpoint.protocol());
                mAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(
            true));
                mAcceptor.bind(endpoint);
                mAcceptor.listen();

                mNextConnection 
            = new Connection(this);
                mAcceptor.async_accept(mNextConnection
            ->getSocket(),
                    boost::bind(
            &ServerFramework::__onConnect, this,
                    boost::asio::placeholders::error));

                mWorkerCount 
            = nWorkers;
                
            if (mWorkerCount == DEFAULT_WORKER_COUNT)
                
            {
                    mWorkerCount 
            = 4;
                }

            }

            open函數(shù)中給io_service的一個(gè)任務(wù)就是在有鏈接訪問服務(wù)器端口的情況下執(zhí)行ServerFramework::__onConnect函數(shù),有一點(diǎn)需要格外注意的,io_service必須時(shí)刻都有任務(wù)存在,否則線程io_service::run函數(shù)將返回,于是線程都會(huì)結(jié)束并銷毀,程序?qū)⑼顺觯裕惚仨毐WC無論何時(shí)都有任務(wù)存在,這樣線程們即使空閑了也還是會(huì)繼續(xù)等待,不會(huì)銷毀。所以,我在ServerFramework::__onConnect函數(shù)中又一次給了io_service相同的任務(wù),即:繼續(xù)監(jiān)聽端口,有鏈接了還是調(diào)用ServerFramework::__onConnect函數(shù)。如果你在ServerFramework::__onConnect執(zhí)行完了還沒有給io_service任務(wù)的話,那么一切都晚了...... 代碼如下:
            void ServerFramework::__onConnect(const BoostSysErr& e)
            {
                
            if (e)
                
            {
                    MOELOG_DETAIL_WARN(e.message().c_str());
                }


                Connection
            * p = mNextConnection;
                mNextConnection 
            = new Connection(this);

                
            // 再次進(jìn)入監(jiān)聽狀態(tài)
                mAcceptor.async_accept(mNextConnection->getSocket(),
                    boost::bind(
            &ServerFramework::__onConnect, this,
                    boost::asio::placeholders::error));

                
            // 處理當(dāng)前鏈接
                __addConnection(p);
                p
            ->start();
            }

            最后,展示一下這個(gè)類的所有成員變量吧:
                // 用于線程池異步處理的核心對(duì)象
                boost::asio::io_service mIoService;

                
            // 網(wǎng)絡(luò)鏈接的接收器,用于接收請(qǐng)求進(jìn)入的鏈接
                boost::asio::ip::tcp::acceptor mAcceptor;

                
            // 指向下一個(gè)將要被使用的鏈接對(duì)象
                Connection* mNextConnection;

                
            // 存儲(chǔ)服務(wù)器鏈接對(duì)象的容器
                ConnectionSet mConnections;

                
            //// 為鏈接對(duì)象容器準(zhǔn)備的strand,防止并行調(diào)用mConnections
                //boost::asio::io_service::strand mStrand_mConnections;

                
            // 為鏈接對(duì)象容器準(zhǔn)備的同步鎖,防止并行調(diào)用mConnections
                boost::mutex mMutex4ConnSet;

                
            // 為控制臺(tái)輸出流準(zhǔn)備的strand,防止并行調(diào)用std::cout
                AsioService::strand mStrand_ConsoleIostream;

                
            // 工作線程的數(shù)量
                uint32 mWorkerCount;



            但愿這篇隨筆也能對(duì)正在研究asio的朋友們有所幫助吧。

            posted @ 2009-06-26 22:14 釀妹汁 閱讀(9913) | 評(píng)論 (15)編輯 收藏

            MySQL的備忘錄

            首先安裝完MySQL5.1.30后,可以進(jìn)入控制臺(tái),輸入 mysql -u root -p然后回車,如果沒有密碼的話,-p似乎就能省掉了。
            進(jìn)入后輸入 show databases命令就可以看到所有的數(shù)據(jù)庫(kù)了。
            然后是新用戶的問題,如果你想添加一個(gè)新的用戶,有很下列三種方法:
            1、直接在mysql數(shù)據(jù)庫(kù)中的user表里直接insert,但是很麻煩
            2、使用GRANT [權(quán)限] ON *.* TO [username]@[客戶端地址] identified by [password]  這樣的命令,具體可以看文檔
            3、使用CREATE USER [用戶名] 這樣的命令創(chuàng)建用戶
            這里要注意的是,第二種方法創(chuàng)建用戶的話,必須帶有密碼,如果你想創(chuàng)建無密碼用戶的話,則必須用第3種方法。
            最后就是給用戶權(quán)限的問題,一般都使用GRANT語(yǔ)句,具體可參考文檔,不過你也可以直接對(duì)db表直接進(jìn)行修改和添加,只要你不怕麻煩。

            posted @ 2009-06-26 21:30 釀妹汁 閱讀(211) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題
            共3頁(yè): 1 2 3 
            亚洲欧美日韩久久精品第一区| 99久久人妻无码精品系列蜜桃 | 美女久久久久久| 久久夜色tv网站| 精品久久久久久综合日本| 国内精品久久久人妻中文字幕 | 91精品国产91久久久久福利| 国产成年无码久久久免费| 欧美精品国产综合久久| 久久久久亚洲AV无码专区首JN | 久久99精品国产自在现线小黄鸭| 精品久久久无码21p发布| 午夜精品久久久久久中宇| 久久妇女高潮几次MBA| 97精品国产97久久久久久免费| 久久香综合精品久久伊人| 久久综合香蕉国产蜜臀AV| 久久99国产综合精品女同| 欧美伊香蕉久久综合类网站| 国产精品成人久久久久久久| 久久午夜综合久久| 久久久久久久女国产乱让韩 | 九九久久99综合一区二区| 国产精品免费久久| 久久久久久午夜精品| 久久久婷婷五月亚洲97号色| 人人狠狠综合久久亚洲婷婷| 欧美日韩精品久久久久| 久久香综合精品久久伊人| 亚洲国产精品久久久久网站 | 久久人人爽人人爽人人爽| 粉嫩小泬无遮挡久久久久久| 91性高湖久久久久| 99久久精品国产一区二区 | 久久精品国产99国产精品| 欧美亚洲国产精品久久| 久久99国产精品久久久| 国产香蕉久久精品综合网| 久久精品国产99国产精偷| 一本色道久久综合狠狠躁篇 | 久久精品一区二区影院 |