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

            前文已經講述,字母全排列是個驚人的數字,即使只遍歷小寫字母和數字6個全排列也有36^6 = 217678233621億多個,7個排列36^7 = 78364164096783億多,8個排列36^8 = 28211099074562.8萬億多個,數字非常驚人。Md5反查是個string-string的映射,16-N個字符的映射,如果考慮hex模式的md5那就是32-N的映射,考慮映射人們最先想到的可能都是數據庫存儲方式,我也首先想到了用數據庫存儲,分別考察了一下sqliteberkeleydb,但測試下來制造數據的速度很慢,sqlite加索引大概只能到5w條記錄/s,不加索引為10w/sberkeleydb用單條模式大概只能到4.5w/s,這個速度已經很慢了,更難于接受的是如果寫1000wsqlite加索引來說不是耗時200s,而是2000s了,也就是說耗時隨單個數據文件記錄的條數增多幾乎成平方模式遞增,而不是簡單的線性遞增,這是很要命的,就算制造1億條數據耗時也是驚人,我的實測中沒有測試過用sqlite制造1000w條以上的數據,在我心目中已經否定了那種模式。雖然我知道很多號稱有多少億條數據的網站其實都是用的數據庫,我不知道他們花了多少時間制造數據,或者幾天,或者幾個月,或者更長時間,反正我對采用普通數據庫模式制造數據完全持否定態度,嵌入式速度太慢,其他數據庫則不光速度慢而且也不適合分布式應用,難道用戶每裝個點還要裝個mysql之類的數據庫,幾乎不可能啊。

            下面說說我的方法,我本來第一版本是計劃先不做文件式數據庫的,第一版本來只規劃了做內存數據,充分榨取每一個字節,關于內存數據庫我實現了好幾個版本,下面分別介紹一下:

            版本1hash模式

            char key[16];做鍵,char pass[n];做內容,由于hash桶占用了一些字節:

                            DWORD h, nKeyLen;               //hash鍵值, 字符串長度

                            DWORD tag;                           //私有值,默認為0提供給外部使用

                            bucket *pListNext;           //hash表雙鏈的下一個節點

                            bucket *pListPrev;           //hash表雙鏈的上一個節點

                            bucket *pNext;                        //拉鏈的下一個節點

                            VALUE second;                        //具體數據

                            _Elem first[0];                 //first

            用這個hash模式大概存儲一個6個字符的串的md5信息花了50個字節,花費太多,結果自然存不了多少數據,該方案作為第一驗證方案,除了花費內存太多還是個能通過的方案。

             

            版本2hash簡化方案

            在上述版本基礎上簡化桶設計,拋棄作為標準桶的一些字段,精簡之后如下:

                            DWORD h;                               //hash鍵值

                            bucket *pNext;                        //拉鏈的下一個節點

                            byte nKeyLen;                  //字符串長度

                            VALUE second;                        //具體數據

                            _Elem first[0];                 //first

            該版本存儲一個6個字符的串的md5信息需要31個字節,比版本1少了很多,進步一些了。

            方案1和方案2速度都很快。

             

            版本3vector方案

            考慮到hash占用內存較多,采用vector方案,直接存儲

            Char mm[16];

            Char pass[n];

            存儲一個6個字符的串的md5信息需要22個字節,該方案排序速度太慢,查找速度肯定也比不上版本1和版本2,之后還測試過將vector里面存儲指針,那種模式每個6個字符的串的md5信息占用內存26個,接近hash版本,排序速度比直接存儲數據的好一點,但也還是很慢,總之這個方案作為一個過度方案最終也被放棄了。

             

             

            方案4:全文件Hash緊縮方案

            以上這些方案的特點是都存儲了char mm[16]; 也就是說存儲部分都有計算出來的md5,經過思考之后覺得可以放棄存儲md5,不存儲md5是個很妙的想法,繼續發揮hash思想,也不保存根據md5計算出來的hash值本身,只將該md5和串的信息關聯到hash值的模所在的索引節點,這樣就將索引節點信息減少到極致:

                    size_t coffset;                  //content offset low

                    unsigned short a:12;       //切分為12, 4

                    unsigned short b:4;         //4,為下一個沖突值的索引序數,如果沒有就為0

                    size_t nextindex;             //沖突條目的存儲序號,為0表示沒有沖突

             

            使用該索引可讓單文件最多支持內容16T,最多687億記錄,具體實現的時候由于全使用文件所以速度比較慢,速度退化到sqlite之類同一級別了,不過這個設計思想為方案5提供了借鑒,如果跟方案5一樣用大塊內存輔助,速度大概可以上升一個級別,不過由于沒有具體實現,待研究之后再做評估。

             

            方案5hash緊縮內存方案

            學習方案4的設計思想,考慮僅在內存里面實現一個緊湊型文件,由于只考慮內存可表示的32位范圍,所以簡化索引節點定義如下:

            Size_t coffset;          pass相對于內容區首的偏移

            Size_t nindex;          沖突節點下一個序,如果為0則表示沒有沖突

            內容區存儲更簡單,每個字符串直接保存,最后的0也保存,這樣每個字符串自然分開,對一個6個字符長的串來說,保存一個信息只需要15個字節,真的是省啊,1億個字符串也只要大約1.5g左右硬盤就夠了。此方案雖然很妙,但實現的時候卻費了一些周折,具體做的時候也做過好幾個版本,由于考慮該方案的內容和索引最后都可以直接保存到文件,所以該方案對位置的保存都用的是相對位置,也由于想讓索引節點信息簡單,最初是讓沖突索引采用線性步長跳躍方法,測試之后發現這個方法速度奇慢,而且還有個非常討厭的問題,隨著數據量的增多沖突擴散越來越厲害,耗時非線性的陡峭增長。放棄這個實現之后還是回到了經典的拉鏈法,拉鏈法速度就是快,但拉鏈法處理索引節點雖然容易,但要讓索引信息可直接保存卻要花一些腦子,最后采用先用內存擴展拉鏈,待全部索引構造好之后再把拉鏈出來的部分重新填到原始索引區中的空區,并修正對應索引相對位置。這個方法的精妙之處在于既省空間又有速度,最令人興奮的是采用該方法耗時隨著數據量的增大是線性增長,最后的實現在我的筆記本上大概100w/s1億條記錄從字母組合到最終生成索引文件也只要不到2分鐘的時間,制造了一些數據之后統計了一下,沖突節點比例大概占26%-35%,也就是說有65%以上的數據只要一次hash就直接命中,平均拉鏈長度1.2左右,最長拉鏈10,總體還是很滿意的。

             

            原本第一版沒有考慮這個可存儲的方案,但花了幾天就搞定了一個基本可用的存儲方案還是很令人興奮的,雖然該存儲方案還有一些問題沒有徹底解決,但已經有進一步處理的辦法,待下一個相對空閑時間段再仔細研究一下,定會有更簡潔的實現做出來,至于待解決的是什么問題以及如何解決那些問題還是等我代碼寫好了再寫出來吧。

            posted @ 2010-10-03 14:18 袁斌 閱讀(196) | 評論 (0)編輯 收藏

            HashCrack程序規劃

             

            最近幾天在思考如何遍歷md5找出原碼字符串,但九十多個可見字符,96^6 782757789696,就算只遍歷6位組合也是非常驚人的巨量數據,單機根本無法完成,根據常用密碼合成規律,我們可以采用分而治之的方法解決,方法大致如下:

            1、 使用很多機器,機器越多覆蓋的范圍越大。

            2、 優先覆蓋最常用的范圍,如全數字組合,小寫字母組合,小寫數字混合組合,大寫字母組合,夾雜一個非字母數字字符的組合,之后覆蓋非常見組合,如所有可見字符的N個全排列。

            3、 采用c/s結構,中心機管理區段分配策略,優先覆蓋常用區段,所有slavemaster一起構成一個覆蓋網。

            4、 不僅支持md5,也支持sha等其他類似算法。

            5、 Masterslave也支持添加字典,為了覆蓋盡可能多的組合,可添加任何合適的字典組合。

             

            實現難點:

            1、 數據組織。

            方案一、考慮過磁盤存儲方案,研究了sqlite,寫效率大概10w/s,加了索引大概5w/ssqlite存儲效率也不是很高,比berkeley存儲浪費很多空間,加了索引后空間放大了一倍。也嘗試過berkeley方案,寫效率大概只有4.5w/s,存儲相對sqlite緊湊一些。但由于寫效率太低,都難于實現我所希望的一個slave一下分配1億數據量的模式(1億數據大概要占磁盤5-10G,最經濟模式大概也要占2.xG)。由于對btree+不太熟悉,暫時還沒有找到高效的存儲方案。

             

            方案二、其實首先是考慮了內存方案,用內存相比磁盤其實要簡單一些,不過受機器可用內存的限制以及客戶接受程度的限制,難于讓一臺slave處理1億以上的數據量,默認大概只能分配2000w-5000w左右的數據量(大概占用內存400M-1.2G)。

             

            以上兩種方案其實選擇方案一更合適一點,因為一般的機器擠2G左右的磁盤基本都沒有問題,甚至20G-200G可能都問題不大,但要持久占用1G內存可能不大好,畢竟大多數用戶比容易接受。第一版暫時用了方案二,待高速寫存儲方案做好后替換一個dll即可(該dll已經留好了接口可直接替換)。

             

            2、 區段劃分

            單純的劃分某一個區段也是比較容易的,如10個數字的8個組合,可用如下方法表示

            Digits = “0123456789”

            Range(Digits, 8, 0, 20000000) 表示digits 8個字母的排列 [0,20000000]

            但將一些常用區段單獨出來之后涉及到和更大范圍字母全排列的重合情況就不大好扣出來,暫時沒有找到較好的表示方法,好在小范圍排列被冗余也問題不是很大,此表示方法待繼續研究,暫時采用冗余方案。

             

            3、 Master 發現機制

            其實這是一個經典的問題,可考慮得很復雜,也可考慮得很簡單,由于我名下幾個域名都被禁止解析了,所以這個問題變得不是那么方便,不過暫時還是用個域名部署一下最為簡單,存儲空間也是個問題,待我聯系幾個朋友看看能不能找到一個合適的存儲地點,待找到后第一版就這么部署出去吧。

             

             

            實現方法:

            由于要有一個中心提供調度方案,因此該系統肯定有一個中心(不管是一個點還是N個點),所以考慮采用c/s模式,第一版采用一個masterNslave的方案。

            master主要實現以下功能:

            1、 覆蓋最常用區段排列,籍此提供最基本的查詢服務。

            2、 支持大量slave接入(暫采用iocp模式接入)。

            3、 提供區段劃分功能,slave接入斷開自動分配區段,優先分配常用區段,其次分配非常用區段。

            4、 查詢轉發功能,接收slave的查詢請求,轉發給其他slave

             

            slave實現以下功能:

            1、 master交互,接收分配的區段,處理區段內的數據并提供該區段數據查詢服務(此功能由一個接口dll實現,可輕易替換)。

            2、 支持查詢功能。

            3、 在客戶端還計劃支持apislaveapiproxyapi通過消息向slave發送查詢請求,slave通過給master發送查詢請求,在整個群落里面提供查詢服務,此功能為該體系的一大亮點,暫時沒考慮做什么限制,主要為吸引用戶提供很主動的編程功能,第一版通過一個cdll提供api調用功能,在此api基礎上用戶應該可以很容易包裝出其他語言的調用接口,如luapython的接口等。

             

             

            進度說明:

            由于該項目只是一個即興性項目,沒打算耗費很多時間,計劃在一周內完成,已經過去了3天,所以在細節上暫時無法抽出很多時間仔細研究,待整體功能成型后看情況再斟酌算法,易改變部分暫時都用接口dll實現,該項目代碼部分大概完成了一半左右,未來2-3天左右大概可以做完第一版。

            posted @ 2010-10-03 14:17 袁斌 閱讀(178) | 評論 (0)編輯 收藏

            Jsonajax領域很流行,記得當時看過它的介紹后很興奮,網上找了一些解析jsonc

             

            c++代碼,不過沒有找到特別好的,有的寫得不錯不過要依賴于boost,有的用c寫的不大好用,好在json語法簡單,參考了一些c/c++json解析代碼做了一個json類,最近又把去年寫的json類修改為unicode下使用,增了一些功能,現在CJsonw可以解析const char *型輸入,也可解析const wchar_t *型輸入,可解析ansi編碼、unicode編碼、utf8編碼的json文件。看看我的CJsonw定義:

             

                    JsonwType type;                     //Json類型, true false null直接由類型表示了

                    DWORD tag;                            //tag,用戶自用值,默認為0

                    union

                    {

                            struct{

                                    wchar_t *cstring;//字符串型值

                                    int clen;            //cstring按照字符計算的分配個數,包括可能的0

                            };

                            double dvalue;          //double

                            struct

                            {

                                    int ivalue;         //int

                                    DWORD dwhigh;       //高部

                            };

                            __int64 i64value;        //int64

                            OBJS *objs;                     //對象型值

                            ARRAYS *arrays;             //數組型值

                    };

            Sizeof(CJsonw) == 16

            OBJS類型描述無序的key-value型數據,ARRAYS描述 array型有序數據,定義如下:

                    typedef CHashiW<CJsonw *, CJsonw *> OBJS;

                    typedef std::vector<CJsonw *> ARRAYS;

            支持以下構造函數:

                    CJsonw(JsonwType t=json_null);

                    CJsonw(int value);

                    CJsonw(__int64 value);

                    CJsonw(float value);

                    CJsonw(double value);

                    CJsonw(const wchar_t *value);

                    //數組型構造函數

                    CJsonw(int *numbers, int count);

                    CJsonw(__int64 *numbers, int count);

                    CJsonw(float *numbers, int count);

                    CJsonw(double *numbers, int count);

                    CJsonw(const wchar_t **strings, int count);

            支持以下賦值函數:

                    bool setnull();

                    bool set(bool value);

                    bool set(int value);

                    bool set(__int64 value);

                    bool set(float value);

                    bool set(double value);

                    bool set(const wchar_t *value);

                    bool set(int *numbers, int count);

                    bool set(__int64 *numbers, int count);

                    bool set(float *numbers, int count);

                    bool set(double *numbers, int count);

                    bool set(const wchar_t **strings, int count);

                   

                    //修改常規值,就是true, false, int, real, string

                    bool setbystring(const wchar_t *value);

             

            支持以下輸入:

                    bool parse(const char *string);

                    bool parse(const wchar_t *string);

                    bool parsefile(FILE *fp);

                    bool parsefile(LPCTSTR filename);

            文件可以ansi編碼、unicode編碼、或者utf8編碼

             

            支持以下wchar_t型輸出:

                    //dump,默認為unicode編碼

                    //uunicode表示字符串中的unicode字符是否按照\uxxxx格式輸出

                    //bDisptrue按照友好格式顯示,會輸出\t換行等方便閱讀

                    //bDispfalse按照緊湊模式顯示,沒有多余字符,方便網絡傳輸等場合

                    bool dump(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=false, bool bDisp=true);

                    //跟上面的dump一樣,但如果成功會在buf里面插入一個'\0'字符

                    bool dump0(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=false, bool bDisp=true);

                    bool save(LPCTSTR filename);

                    bool save(FILE *fp);

            保存到文件默認為UNICODE格式

             

            支持以下ANSI型輸出:

                    //a系列dumpansi編碼輸出

                    //bDisptrue按照友好格式顯示,會輸出\t換行等方便閱讀

                    //bDispfalse按照緊湊模式顯示,沒有多余字符,方便網絡傳輸等場合

                    bool dumpa(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=true, bool bDisp=true);

                    //跟上面的dump一樣,但如果成功會在buf里面插入一個'\0'字符

                    bool dumpa0(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=true, bool bDisp=true);

            ANSI型輸出主要用在節省網絡帶寬或者和其他系統交換數據的情況下。

             

            支持以下類型判別函數:

                    //類型判別函數

                    bool IsArray() const { return type==json_array; }

                    bool IsObject() const { return type==json_object; }

                    bool IsInt() const { return type==json_int; }

                    bool IsReal() const { return type==json_real; }

                    bool IsNumber() const { return IsInt()||IsReal(); }

                    bool IsNull() const { return type==json_null; }

                    bool IsTrue() const { return type==json_true; }

                    bool IsFalse() const { return type==json_false; }

                    bool IsString() const { return type==json_string; }

             

            支持以下一些直接取值函數:

                    const wchar_t *getordef(const wchar_t *strdef)

                    int getordef(int idef)

                    __int64 getordef(__int64 idef)

                    double getordef(double ddef)

                    bool getordef(bool bdef)

                    //array的元素

                    CJsonw *get(int n)

                    CJsonw *operator[](int n) const

                    //obj的元素

                    CJsonw *get(const wchar_t *name)

                    CJsonw *operator[](const wchar_t *name) const

             

            支持以下取array型子元素數據的函數:

                    const wchar_t *getordef(int n, const wchar_t *strdef)

                    int getordef(int n, int idef)

                    __int64 getordef(int n, __int64 idef)

                    double getordef(int n, double ddef)

                    bool getordef(int n, bool bdef)

             

            支持以下取obj型子元素數據的函數:

                    const wchar_t *getordef(const wchar_t *name, const wchar_t *strdef)

                    int getordef(const wchar_t *name, int idef)

                    __int64 getordef(const wchar_t *name, __int64 idef)

                    double getordef(const wchar_t *name, double ddef)

                    bool getordef(const wchar_t *name, bool bdef)

             

            支持以下obj遍歷函數:

                    //遍歷函數,最常見寫法:

                    //for(CJsonw::OBJIT *p=xxx.FirstObj(); p; p=p->next())...

                    OBJIT *firstobj()

             

                    //arrayobject元素個數,string類型返回分配的字符個數(包括可能的),其他類型都返回

                    int size() const

             

            另外支持一些增加array子元素函數:

                    bool add(CJsonw *pnode)

                    bool del(int n, bool bfree=true)

                    bool addnull(){ return add(new CJsonw(json_null)); }

                    bool addtrue(){ return add(new CJsonw(json_true)); }

                    bool addfalse(){ return add(new CJsonw(json_false)); }

                    bool add(int value){ return add(new CJsonw(value)); }

                    bool add(__int64 value){ return add(new CJsonw(value)); }

                    bool add(float value){ return add(new CJsonw(value)); }

                    bool add(double value){ return add(new CJsonw(value)); }

                    bool add(const wchar_t *value){ return add(new CJsonw(value)); }

             

            也支持obj增加刪除子對象函數:

                    bool addobj(const wchar_t *name, CJsonw *pnode)

                    bool delobj(const wchar_t *name, bool bfree=true)

                    bool addobjnull(const wchar_t *name){ return addobj(name, new CJsonw(json_null)); }

                    bool addobjtrue(const wchar_t *name){ return addobj(name, new CJsonw(json_true)); }

                    bool addobjfalse(const wchar_t *name){ return addobj(name, new CJsonw(json_false)); }

                    bool addobj(const wchar_t *name, int value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, __int64 value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, float value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, double value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, const wchar_t *value){ return addobj(name, new CJsonw(value)); }

             

            還有一些特殊函數:

                    //計算整個樹的crc

                    DWORD calccrc();

                    //計算整個樹的md5,要求md5不少于個字節

                    byte *calcmd5(byte *md5);

                    //計算hex表示的md5,不寫尾部,要求md5hex不少于個字符

                    char *calcmd5hex(char *md5hex, const byte x='x');

                    //計算hex表示的md5,寫尾部,要求md5hex不少于個字符

                    char *calcmd5hex0(char *md5hex, const byte x='x');

             

             

            json類上花了較多時間,主要是覺得這個類很有用,可以描述任意對象,易保存易傳輸易構造,對速度要求不苛刻的應用程序用json作為基本數據結構很合適,配合json里面的data自定義字段理論上支持描述任意對象,配合使用一些cache可擴大json類的使用范圍,用它取代ini xml等配置簡直是大材小用,用json類來做stringtable簡直就是小菜一碟,而且還是hash級高效率,絲毫不比手工做一個hash_map<,>表差。

            在實際應用中,去年有一個網絡驗證的項目就大量使用了這個類,配置、幫助都是json格式,應用中管理大量對象的內存數據庫也是用了json類,編碼后直接網上傳輸,server內部也是一個json對象直接管理了大量用戶的信息,非常方便,可以說用json類使得這個程序少寫了大量代碼,也使得整個項目只用了1個月時間就做出來了,還部署成master – master- slave(N)模式穩定運行了將近1年時間。

            在另一些網絡應用中,俺將json格式數據作為變長包使用,前面俺寫過一篇短文介紹了變長包最常見的幾種格式,分別是:

            1、 key\0value\0…

            2、 json格式

            3、 xml格式

            使用json格式作為變長包現在很流行,這也是大量ajax所采用所依賴的技術,qq種菜,google搜索預列表都是采用json格式的。

            posted @ 2010-10-03 14:17 袁斌 閱讀(910) | 評論 (0)編輯 收藏

            寫了tmpool之后又發現居然有tcmalloc,而且比牛逼的ptmalloc好很多,真感嘆啊,世界上好東西很多,但需要智慧的眼光去發現。在linux下簡單比較了一下malloc和tcmalloc,快的真不是一點點啊,看到好多人用tcmalloc去重編譯mysql, squid,nginx等。簡單看了下tcmalloc的原理,比我寫的tmpool要多一些整理的功能,大概tmpool就是tcmalloc在win下的子集,俺的tmpool區區800行代碼自然是不能去跟tcmalloc比的,不過對付一般的server端程序還是夠用的,經過一段時間的使用效果也還可以,待有時間對比下俺的tmpool和tcmalloc。

            posted @ 2010-10-03 14:16 袁斌 閱讀(1097) | 評論 (0)編輯 收藏

            簡單總結下asp.net狀態維持方法如下:

            client端狀態
            1、ViewState
            2、ControlState
            3、Hidden Field (post 模式)
            4、Cookie
            5、QueryString (get 模式)

            server端狀態
            1、Application (全局)
            2、Cache (全局)
            3、Session (current session,配合后臺驅動可將session持續化到很多地方,如xml,
            或者db、或者memcached 等地方)
            4、配置文件(asp.net有一個sqlprofileProvider類使您可將配置文件數據保存到sql數據庫中)
            5、db

            對保持連接的c/s程序來說,client端狀態我們不是特別關心,除了cookie也有一些參考意義,其他幾種方法很難直接在普通cs程序里面對應,對server端程序開發來說,asp.net的server端數據持續方法對我們很有參考價值,對一般的游戲程序來說,db是必然會用的,配置文件型的也可參考使用,session型的很多程序都在使用,application型的緩存估計也有很多程序在用,更有價值的是cache型,我們一般的s程序基本都沒有實現時效性cache和文件觸發性cache,asp.net的cache對我們很有參考價值。當然我們不必生搬硬套的照搬web上的概念,只要學到精髓就可以了,總之,還是我堅持的那句話,俠義地說是從web架構學習server端程序設計,更廣義地說是從web架構學習一般網絡應用程序設計。

            posted @ 2010-10-03 14:16 袁斌 閱讀(168) | 評論 (0)編輯 收藏

            我一直堅持一個觀點,從web體系學習服務器端程序設計,web作為發展最早也是前景最廣闊的internet模型,幾乎支撐了網絡世界一半以上的應用,其他email ftp等傳統應用雖然產生時間也很早但幾乎都很沒落,只有web風采依舊,蓬勃發展,從apache到lighttp到nginx等,一個接一個高性能的web服務器程序分別被開發出來,上層應用cgi, isapi(nsapi), fastcgi助力,html協議也在不斷發展,html5也要登堂亮相,各種腳本語言爭相斗艷,python、php、java、asp.net等。web應用支持了目前最大規模的數據google,支持了最大量用戶的訪問,因此各種存儲、云計算等都是首先在web領域獲得應用,可以說web就是it領域的創新源泉,看下apache下面有多少項目就可見一般。web體系可謂博大精深,從web體系學習服務器端程序設計是學無止境的,從nginx等服務器程序設計上可學習server程序如何分塊、如何高效,從isapi/nsapi模型上可學習如何用進程內模塊擴展應用,從fastcgi可學習如何用進程外模塊擴展應用,從各種cache方案中可學習如何為server端提速,從各種腳本應用上可學習如何為server端程序二次開發助力,web是源泉,web的各種這方式幾乎概括了server端程序的各種架構模型。當然一般自定義協議服務器和web還是有些地方不同的,最顯著的區別一般也就在于協議不一樣,另外就是web是無狀態一般不保持連接,因此web需要傳遞各種session等維持狀態的數據,總之從web可學習的地方實在是太多。

            簡單類比下web領域開發和一般server的擴展

            nginx模塊/apache模塊            server程序+plugin

            cgi                                      fork子進程

            fastcgi                                 server proxy模式,由于fastcgi可網絡方式部署,所以很容易在一個局域網內部實現一個ioserver+N logicserver模型

            簡單類比就可知道,如果一個server程序只要能很方便的支持plugin+fastcgi就可適應幾乎所有各種需求,可惜的是一般的server程序幾乎都不支持這兩個模式的擴展,大多數gameserver只支持lua等腳本,說實在的,支持個腳本跟支持fastcgi和plugin模塊相比還是差很多,如果支持fastcgi或者plugin只要做個plugin就支持lua了。

            posted @ 2010-10-03 14:15 袁斌 閱讀(224) | 評論 (0)編輯 收藏

            常見cs程序自定義數據包描述

             

            常見cs程序自定義包可分為塊型包、非塊型包,非塊型包如http協議的,用\r\n\r\n結束,我們這里重點討論塊型包,塊型包常見頭部如下:

            Struct PKHEAD

            {

                    Union

            {

                            DWORD type;

                            Struct

            {

                    WORD mtype;

                    WORD stype;

            };

                    };

                    DWORD len;

                    Char buf[0];

            };

            內容buf部分常見組織方式莫過于定長、變長兩種。定長的很簡單,如struct item{…};作為內容部分,如果不涉及到高低序問題很好辦,涉及到序的時候轉換一下。變長部分常見組織方式有這么一些經典方法:

            1、 Content1 \0 content2 \0 content3 \0 …

            2、 json描述。

            3、 xml描述。

            方法1是效率很高的,對ansi型字符串或者utf8型字符串都沒有問題,對utf16型字符串不行。解析這類變長部分的時候特別要注意包尾部的0,或者在緩沖區外部總保證存在一個0,或者保證包內尾部總存在一個結尾0,總之最后一個string要保證有一個合法的0結束,當然可能涉及到一些數值型到string型的轉換可能會導致效率下降,1的缺點在于只有一個層次。如果將內容看作key1\0value1\0key2\0value2\0…可解決無序問題,但終歸只有一個層次,不方便表示樹形數據。

            方法2的效率介于13之間,2由于描述很簡潔,解析也是比較快的,比1好在可以解析任意層數據,嵌套N層都無所謂,閱讀也很方便,解析的時候如果原始緩沖不釋放可讓字符串不復制直接記錄在原始緩沖中的指針,這樣可進一步提高解析效率。QQ種菜的通訊協議就是json格式的,閱讀很方便,解析效率也可以,總的效率適中。

            方法3的解析效率是最低的,好在xml描述性也比較強,解析代碼也很多,跟上層應用交互的時候也比較方便,作為一個支持變長的選擇也是可行的,不過如果特別在意效率的情況下避免使用,xml的解析效率比 2低了近一個數量級,比1可能低近2個數量級。

             

            當然自定義包還有更多格式選擇,標準協議也有很多如im 里面常見的xmppgoogleprotocol buffers等,還有json的一些擴展協議,如bjson等,如果只是處理一般的網游數據可能用不上這么復雜的協議,用上面提到的定長struct+1 or 2 or 3基本可以解決所有協議需求。也見到一些朋友自定義類型信息描述格式,個人覺得或許沒有必要,特別是json如此流行的情況下再自己定義似乎有重復發明輪子的嫌疑,當然具體情況具體對待,一切以滿足需求為目標。

            posted @ 2010-10-03 14:15 袁斌 閱讀(321) | 評論 (0)編輯 收藏

            我寫東西一般是即興性創作,一般在走路的時候很容易產生各種想法,高興的時候到家或到工作的地方馬上就開寫,幾分鐘就將想法記錄下來,由于寫得快也不檢查,所以看上去可能不是很流暢,或者說得不是很清楚,甚至還有很多錯別字等,請見諒。如關于某個技術問題想和我深入探討請和我直接聯系,qq:345585946

            posted @ 2010-10-03 14:14 袁斌 閱讀(125) | 評論 (0)編輯 收藏

            Server模塊如果僅僅作為一個lib包裝出來自然不是最好,雖然可在c++工程很容易使用,效率也比較高,但要使用到其他語言上去就沒有辦法,如果包裝一下自然是最好的,但如何包裝呢,包裝成一個什么樣子也是很重要的,最常見的包裝自然是包裝成一個dll,輸出一些接口,其他上層模塊在該接口的基礎上使用。最簡單的包裝一般可輸出如下一些接口,

             

            Public IServer:

            {

            Virtual void StartServer(LPCTSTR ports, LPCTSTR udpoorts, int iothreads, int syncthreads, int asyntchreads);

            Virtual void StopServer();

                     Virtual IClient *CreateClient();

                     Virtual void CloseClient(IClient *);

                     Virtual void OnCloseClient(IClient *);

                     Virtual void OnConnectClient(IClient *);

                     Virtual void PostSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam)

                     Virtual void PostAsyncEvent(DWORD event, WPARAM wparam, LPARAM lParam);

                     Virtual void OnAsyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void OnSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void OnTimer(UINT uid);

                     Virtual void AddTimer(UINT uid, DWORD tk1, DWORD duetk);

            };

             

            Public IClient

            {

                     Virtual bool SendData(void *pdata, int len);

                     Virtual bool SendFile(LPCTSTR lpfilename);

                     Virtual bool SendFile(HANDLE hFile);

                     Virtual bool SendMsg(PKHEAD *ph);

                     Virtual bool SendMsg(PKHEAD *ph, void *pdata, int len);

                     Virtual bool SendMsg(PKHEAD *ph, void *pdata, int len, byte encrypt, byte compress);

                     Virtual void DelayClose();

                     Virtual void OnDelayClose();

                     Virtual void OnClose();

                     Virtual void OnConnect();

                     Virtual void OnAsyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void OnSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void PostSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void PostAsyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void SetTag(DWORD wParam);

                     Virtual DWORD GetTag();

                     Virtual long GetId();

            };

             

            IServer *DllCreateObject();

             

             

            通過結合LoadLibrary并提供一個類似DllCreateObject的形式可很容易的 模擬類com實現,上層可很容易的是復用dll的實現。

            posted @ 2010-10-03 14:14 袁斌 閱讀(153) | 評論 (0)編輯 收藏

            服務器程序可以使用以下腳本

            1、 wow大規模的使用lua,已經導致lua成為網絡游戲領域第一大腳本語言,速度和簡潔性是它的突出特點,豐富的包裝庫也使得它的使用很簡單,但庫偏少和沒有完整的面向對象特性也導致它不優雅,有的時候需要自己包裝太多東西,總之還不是一個完美的東西。Tcc, python等也是服務器腳本的可選語言,tcc速度更快,python庫豐富。

            2、 我一直說server程序的開發可類比web領域的開發,web提供了豐富的腳本,如phpc#等,在一般的server程序里面集成php也是很容易的,php提供了豐富的庫,如果要開發和web交互頻繁的程序那么php的優勢就更明顯了,使用php也可以跟php作為普通web腳本一樣有幾個選擇,如可當作進程內模塊使用、也可以當作cgi使用,也可以當做fastcgi使用,不過作為普通服務器程序和一般的web程序還是有一些區別的,主要有兩個區別,那就是web是無狀態的,一般的server可能有狀態也可能無狀態,但大多都是有狀態的,第二個不同就是web支持的是http協議,而一般的網游支持的是自定義協議,用phpserver端腳本除了這兩個地方要注意之外就和在web上使用沒多大區別了。包裝好和主模塊的交互就一切搞定了。

            3、 2可知道,不僅僅是php可作為server程序的腳本,c#包括所有.Net平臺支持的語言都可以作為server程序的腳本,c#隨著4.0的發布已經成為.net平臺上的首選語言,優雅的語法和高效的性能讓它激動人心,比php lua等高級了許多,也高效了許多,說它是明星語言一點不過分,如果server可以在.net平臺上,那么c#幾乎是最優的腳本語言,同理vb.net c/clr等只要是.net平臺支持的語言也都可以作為腳本,最典型的支持我們可以從sqlserver了解到,sqlserver支持clr型存儲過程,這就是將.net作為腳本的典范啊。

            4、 其實最簡單的使用dll動態裝入模型也可支持server端的靈活性,而且兼顧了效率,最簡單的處理可以這樣,每次調用dll部分的時候都LoadLibrary,用完之后FreeLibrary,雖然這樣損失了效率,但靈活性比較好,要更新也很容易,當然如果管理到僅在dll更新的時候才重新裝入可讓效率更高,總之這種模型雖然沒有什么人在使用,但其實不失為一種很有效的模型,開發效率和執行效率都比較高,雖然看上去不如用腳本那么優雅。

            posted @ 2010-10-03 14:13 袁斌 閱讀(369) | 評論 (0)編輯 收藏

            僅列出標題
            共4頁: 1 2 3 4 
            久久国产亚洲精品| 97精品伊人久久大香线蕉app| 99久久国产亚洲高清观看2024| 天天综合久久久网| 久久青青草原精品国产不卡| 亚洲成av人片不卡无码久久| 久久一日本道色综合久久| 2021国产成人精品久久| 久久久这里只有精品加勒比| 国产精品免费福利久久| 免费一级欧美大片久久网 | 欧美国产精品久久高清| 色偷偷88888欧美精品久久久| 国内精品九九久久久精品| 污污内射久久一区二区欧美日韩 | 久久久精品久久久久影院| 久久国产色AV免费看| 久久久这里有精品| 久久久精品久久久久特色影视| 一本色道久久综合亚洲精品| 精品无码久久久久久久动漫| 久久精品国产亚洲AV无码娇色| 国产成人精品久久一区二区三区av| 99精品国产综合久久久久五月天| 国产亚洲美女精品久久久| 精品少妇人妻av无码久久| 欧美一区二区久久精品| 国产精品热久久毛片| 91久久婷婷国产综合精品青草| 热RE99久久精品国产66热| 狠狠色综合网站久久久久久久| 国产精品久久久久久一区二区三区| 亚洲精品乱码久久久久久蜜桃图片| 久久久久国产| 久久国产热这里只有精品| 国产精品青草久久久久福利99 | 久久久久久亚洲AV无码专区| 亚洲人成电影网站久久| 久久亚洲精品国产亚洲老地址 | 久久精品免费一区二区| 怡红院日本一道日本久久|