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

            qiezi的學(xué)習(xí)園地

            AS/C/C++/D/Java/JS/Python/Ruby

              C++博客 :: 首頁(yè) :: 新隨筆 ::  ::  :: 管理 ::

            一、問(wèn)題。

            這段時(shí)間考慮實(shí)現(xiàn)一個(gè)純C++的分布式服務(wù)包裝庫(kù),簡(jiǎn)要描述如下:

            有如下類(lèi)和函數(shù):

            struct?Test
            {
            ????
            void?test1?(/*in*/?int?v1,?/*in*/?int*?v2);
            ????
            int?test2?(/*in*/?int&?v1,?/*out*/?int*?v2);
            };

            int?test_func?(/*in*/?int*?v1,?/*inout*/?string*?v2);


            想把它們作為服務(wù)發(fā)布出去,以SOAP或其它方式。發(fā)布為一個(gè)TestService,并讓它攜帶多一些信息:

            struct?TestService
            {
            ????
            void?test1?(in<int>?v1,?in<int>?v2);
            ????
            int?test2?(in<int>?v1,?out<int>?v2);
            ????
            int?test_func?(in<int>?v1,?inout<string>?v2);
            };


            C++有許多工具、庫(kù)來(lái)做到這點(diǎn),但是,都需要生成一堆代碼,很是不爽。

            其它語(yǔ)言,比如python, java, c#等,都可以通過(guò)自省機(jī)制,拋開(kāi)IDL在語(yǔ)言?xún)?nèi)實(shí)現(xiàn)。

            C++并非不能做這個(gè),它只是缺少足夠的類(lèi)型信息。比如上面的例子,如果要發(fā)布為服務(wù),那么至少應(yīng)該把它的參數(shù)、返回值搞得明確些,否則要么會(huì)造成不必要的參數(shù)傳遞,要么會(huì)產(chǎn)生錯(cuò)誤(把OUT參數(shù)取值可不是安全的)。

            比如上面出現(xiàn)的int, int&, int*,在作為in參數(shù)時(shí),我們是想傳遞它的值,類(lèi)型為int。而int*和string*作為out參數(shù)時(shí),我們想讓它傳遞指針或引用,當(dāng)調(diào)用返回時(shí),我們給它賦值。

            C++語(yǔ)言的類(lèi)型極為豐富,卻沒(méi)有描述一個(gè)參數(shù)到底是in還是out。java也沒(méi)有,但它可以正常序列化一個(gè)null值,在C++中,這可能存在一些麻煩。

            再考慮一下char*類(lèi)型,假如它是in參數(shù),那么它是要傳遞一個(gè)字符還是一個(gè)字符串?C++語(yǔ)言沒(méi)有對(duì)它進(jìn)行描述。

            所以要實(shí)現(xiàn)一個(gè)分布式服務(wù)包裝(或代理)庫(kù),必須讓發(fā)布者提供這些信息。

            我們知道,要查詢(xún)一個(gè)遠(yuǎn)程服務(wù),必須查詢(xún)相應(yīng)主機(jī)端口,獲取服務(wù)信息。最簡(jiǎn)單的服務(wù)信息包括:服務(wù)列表,每個(gè)服務(wù)中的方法列表,方法的類(lèi)型(包括參數(shù)和返回值類(lèi)型,in/out信息等)。

            實(shí)際上,我們是要為C++增加一些簡(jiǎn)單的自省能力。上面那個(gè)服務(wù)發(fā)布接口,實(shí)際上離這個(gè)要求還有很遠(yuǎn),再來(lái)看一下:

            struct?TestService
            {
            ????
            void?test1?(in<int>?v1,?in<int>?v2);
            ????
            int?test2?(in<int>?v1,?out<int>?v2);
            ????
            int?test_func?(in<int>?v1,?inout<string>?v2);
            };


            可以想見(jiàn),它是沒(méi)有一點(diǎn)自省能力的,我們?nèi)绾蜗蛩樵?xún),它的名字?它的方法列表?方法的類(lèi)型?它如何與Test類(lèi)的成員函數(shù)以及test_func函數(shù)關(guān)聯(lián)?

            二、方向。

            要讓上面那個(gè)服務(wù)具有自省能力,要做的擴(kuò)充其實(shí)并不多。考慮下面的代碼:

            struct?TestService?:?public?Service
            {
            ????TestService?();
            ????Method?
            <void(in<int>,?in<int>)>?test1;
            ????Method?
            <int(in<int>,?out<int>)>?test2;
            ????Method?
            <int(in<int>,?inout<string>)?test_func;
            };


            這幾個(gè)Method可以用自己寫(xiě)的委托類(lèi)來(lái)做。

            1、假如我們?cè)赥estService的構(gòu)造函數(shù)里給它分配一個(gè)“TestService”名字,并且Service類(lèi)實(shí)現(xiàn)了查詢(xún)名字的接口,那么它就知道它自己的名字了。

            2、假如在TestService的構(gòu)造函數(shù)里為各個(gè)Method分配名字,并且注冊(cè)到TestService,那么它就能夠查詢(xún)方法列表。

            3、方法的類(lèi)型?通過(guò)模板方式,把各個(gè)參數(shù)類(lèi)型收集起來(lái),給個(gè)字符串名稱(chēng)就可以了。

            使用宏來(lái)實(shí)現(xiàn),大概可以寫(xiě)成這樣:

            BEGIN_SERVICE?(TestService)
            ????METHOD?(
            void(in<int>,?in<int>),?test1,?&Test::test1)
            ????METHOD?(
            int(in<int>,?out<int>),?test2,?&Test::test2)
            ????METHOD?(
            int<in<int>,?inout<string>),?test_func,?test_func)
            END_SERVICE?()


            通過(guò)上面這幾個(gè)宏,我們能夠生成TestService聲明。

            不過(guò),有幾個(gè)問(wèn)題,羅列如下,并一一解決它:

            1、如何把函數(shù)指針傳給它?如何把方法名稱(chēng)傳給它?
            這個(gè)只是C++語(yǔ)言為我們?cè)黾恿艘恍┞闊覀儫o(wú)法在定義成員的地方調(diào)用它的構(gòu)造函數(shù),不過(guò)這并不會(huì)造成多大障礙。
            上面的METHOD宏如果只是生成類(lèi)的聲明,那么函數(shù)指針可以省略。我把它加上的原因是,它可以被我用Ctrl+C, Ctrl+V這種世界上最先進(jìn)的技術(shù)原樣拷貝下來(lái),并且通過(guò)簡(jiǎn)單修改的方法實(shí)現(xiàn)這種世界上最先進(jìn)的重用。

            上面的代碼經(jīng)過(guò)修改,結(jié)果就成這樣:

            BEGIN_SERVICE?(TestService)
            ????METHOD?(
            void(in<int>,?in<int>),?test1,?&Test::test1)
            ????METHOD?(
            int(in<int>,?out<int>),?test2,?&Test::test2)
            ????METHOD?(
            int<in<int>,?inout<string>),?test_func,?test_func)

            ????BEGIN_DEFINE?(TestService)
            ????????METHOD_DEFINE?(
            void(in<int>,?in<int>),?test1,?&Test::test1)
            ????????METHOD_DEFINE(
            int(in<int>,?out<int>),?test2,?&Test::test2)
            ????????METHOD_DEFINE(
            int(in<int>,?inout<string>),?test_func,?test_func)
            ????END_DEFINE?()

            END_SERVICE?()


            看上去對(duì)應(yīng)得非常整齊,修改起來(lái)也比較簡(jiǎn)單。上面那部分被擴(kuò)充為如下代碼:

            struct?TestService?:?public?Service
            {
            ????Method?
            <void(in<int>,?in<int>)>?test1;
            ????Method?
            <int(in<int>,?out<int>)>?test2;
            ????Method?
            <int(in<int>,?inout<string>)?test_func;
            ????TestService?()
            ????:?Service?(
            "TestService")
            ????{
            ????????test1.setName?(
            "test1");
            ????????test1.setMethod?(
            &Test::test1);
            ????????
            this->registerMethod?(&test1);
            ????????test2.setName?(
            "test2");
            ????????test2.setMethod?(
            &Test::test2);
            ????????
            this->registerMethod?(&test2);
            ????????test_func.setName?(
            "test_func");
            ????????test_func.setMethod?(test_func);
            ????????
            this->registerMethod?(&test3);
            ????}
            };


            基本上需要的東西都在這里了。

            2、客戶(hù)端的問(wèn)題。

            上面這種映射,直接拿到客戶(hù)端會(huì)有問(wèn)題,Test類(lèi)和test_func函數(shù)我們并不打算交給客戶(hù)端,所以使用函數(shù)指針會(huì)出現(xiàn)鏈接錯(cuò)誤。

            實(shí)際上客戶(hù)端不需要這個(gè),我們想辦法把它拿掉就行了。客戶(hù)端實(shí)際需要生成的代碼如下:

            struct?TestService?:?public?Service
            {
            ????Method?
            <void(in<int>,?in<int>)>?test1;
            ????Method?
            <int(in<int>,?out<int>)>?test2;
            ????Method?
            <int(in<int>,?inout<string>)?test_func;
            ????TestService?()
            ????:?Service?(
            "TestService")
            ????{
            ????????test1.setName?(
            "test1");
            ????????
            this->registerMethod?(&test1);
            ????????test2.setName?(
            "test2");
            ????????
            this->registerMethod?(&test2);
            ????????test_func.setName?(
            "test_func");
            ????????
            this->registerMethod?(&test3);
            ????}
            };


            還是上面提到的,C++給我們帶來(lái)的麻煩。這次需要另一組宏來(lái)完成它:

            BEGIN_SERVICE_D?(TestService)
            ????METHOD_D?(
            void(in<int>,?in<int>),?test1)
            ????METHOD_D?(
            int(in<int>,?out<int>),?test2)
            ????METHOD_D?(
            int(in<int>,?inout<string>),?test_func)

            ????BEGIN_DEFINE_D?(TestService)
            ????????METHOD_DEFINE_D?(
            void(in<int>,?in<int>),?test1)
            ????????METHOD_DEFINE_D(
            int(in<int>,?out<int>),?test2)
            ????????METHOD_DEFINE_D(
            int(in<int>,?inout<string>),?test_func)
            ????END_DEFINE_D?()

            END_SERVICE_D?()


            METHOD*和METHOD_DEFINE*宏的參數(shù)都有一些多余的信息,沒(méi)有去掉是因?yàn)榉旁谝黄鹑菀卓吹綄?xiě)錯(cuò)的地方。(這個(gè)技巧來(lái)源于前幾天看的一篇BLOG,很報(bào)歉沒(méi)有記下地址)

            3、使用的問(wèn)題。

            如何才能比較方便地使用?我考慮了下面這種方式:

            template?<class?T>
            struct?IProxy;

            template?
            <class?T>
            struct?SOAPProxy;

            SOAPProxy?
            <TestService>?service;
            service.connect?(
            5000,?"localhost");
            int?a=0;
            int?*n?=?&a;
            service.test1?(
            3,?n);
            service.test1?(
            3,?*n);
            service.test2?(
            3,?n);
            service.test2?(
            3,?*n);
            service.test2?(
            3,?NONE);
            //


            Method::operator ()的各個(gè)參數(shù)都將可以接受相容的類(lèi)型,像上面一樣,因?yàn)樵赥estService中我們已經(jīng)定義了它要傳輸?shù)闹档念?lèi)型。

            a.NONE是什么?其實(shí)是為異步調(diào)用考慮的。假如指定某個(gè)OUT參數(shù)為NONE,則這個(gè)參數(shù)的值并不真正的OUT,而是保存在Method中。實(shí)際上Method中保存每個(gè)參數(shù)的值。

            b.Method與Service如何發(fā)生關(guān)系?
            從TestService的定義中我們知道,Method向Service注冊(cè)自己以實(shí)現(xiàn)自省,但它同時(shí)也會(huì)保存Service的指向。
            我們的Proxy實(shí)際上是一個(gè)繼承模板,上面并沒(méi)有把它指出來(lái)。它的定義是:

            template?<class?T>
            class?XProxy?:?public?T
            {
            ????
            //
            };


            所以我們的TestService其實(shí)也是模板類(lèi),它將使用XProxy中定義的序列化類(lèi)。XProxy將實(shí)現(xiàn)Service基類(lèi)中序列化虛函數(shù)以及調(diào)用虛函數(shù)。

            當(dāng)一個(gè)Method調(diào)用時(shí),它會(huì)調(diào)用Service的序列化,由于被重寫(xiě)了,所以調(diào)用的是XProxy中的序列化方法。這個(gè)方法會(huì)把這個(gè)Method的各in/inout參數(shù)序列化,然后執(zhí)行遠(yuǎn)程調(diào)用,再把調(diào)用結(jié)果反序列化給inout/out參數(shù)。

            4、其它想法。

            在考慮上面的定義方式時(shí),我也考慮了其它方式,主要是返回值處理的方法,簡(jiǎn)述如下。

            前面我們假設(shè)了一段將被開(kāi)放為遠(yuǎn)程服務(wù)的代碼:

            struct?Test
            {
            ????
            void?test1?(/*in*/?int?v1,?/*in*/?int*?v2);
            ????
            int?test2?(/*in*/?int&?v1,?/*out*/?int*?v2);
            };

            int?test_func?(/*in*/?int*?v1,?/*inout*/?string*?v2);


            在前面的做法中,我們的服務(wù)描述是放在那一組宏里面,好處是不用改這段代碼,壞處就是代碼定義的地方和描述不在一起,協(xié)調(diào)可能會(huì)有一些不便。

            我也考慮了另一種做法:

            struct?Test
            {
            ????idl?
            <void(in<int>,?in<int>)>?test1?(int?v1,?int*?v2);
            ????idl?
            <int(in<int>,?out<int>)>?test2?(int&?v1,?int*?v2);
            };

            idl?
            <int(in<int>,?inout<string>)?test_func?int*?v1,?string*?v2);


            對(duì)于實(shí)現(xiàn)代碼,只需要修改返回值為void的函數(shù),把return;修改為return VOID;,并且為沒(méi)有寫(xiě)此語(yǔ)句的分支加上此句。

            VOID是一個(gè)特殊類(lèi)型的靜態(tài)變量,專(zhuān)為void返回值的函數(shù)設(shè)定。

            這種做法修改了原有的代碼,不過(guò)在定義服務(wù)時(shí)可以節(jié)省一些工作:

            BEGIN_SERVICE?(TestService)
            ????METHOD?(test1,?
            &Test::test1)
            ????METHOD?(test2,?
            &Test::test2)
            ????METHOD?(test_func,?test_func)

            ????BEGIN_DEFINE?(TestService)
            ????????METHOD_DEFINE?(test1,?
            &Test::test1)
            ????????METHOD_DEFINE?(test2,?
            &Test::test2)
            ????????METHOD_DEFINE?(test_func,?test_func)
            ????END_DEFINE?()

            END_SERVICE?()


            它所需要的函數(shù)類(lèi)型,將由函數(shù)指針推導(dǎo)。

            在G++編譯器下,可以使用typeof來(lái)獲得函數(shù)指針的類(lèi)型而不需要真得獲得函數(shù)指針值,不過(guò)目前僅僅在G++下可用。(順便說(shuō)一下,typeof已經(jīng)列入c++0x)

            最終我放棄了這個(gè)想法,畢竟它要修改現(xiàn)有的代碼,某些情況下這是不可能的,而且typeof目前也不能跨編譯器。

            三、實(shí)現(xiàn)。

            老實(shí)說(shuō)我現(xiàn)在還沒(méi)有一份完整的或半完整的實(shí)現(xiàn),大部分想法還在頭腦中,測(cè)試代碼倒是寫(xiě)了不少,主要是用來(lái)測(cè)試上述想法能否實(shí)現(xiàn),我想大部分情況都已經(jīng)測(cè)試了,只需要有時(shí)間來(lái)把它實(shí)現(xiàn)出來(lái)。

            這是我近期要做的事之一,爭(zhēng)取月內(nèi)把它做完罷。

            posted on 2005-09-15 01:27 qiezi 閱讀(1013) 評(píng)論(4)  編輯 收藏 引用 所屬分類(lèi): 自家破爛C++asgard項(xiàng)目
            国产精品乱码久久久久久软件| 欧美日韩精品久久久免费观看| 精品综合久久久久久97| 久久男人中文字幕资源站| 成人国内精品久久久久影院VR| 国产69精品久久久久777| 久久香蕉国产线看观看精品yw| 伊人久久大香线蕉av不卡| 久久人人爽人人爽人人爽 | 中文精品久久久久国产网址| 久久精品国产亚洲av日韩| 潮喷大喷水系列无码久久精品 | 99久久婷婷国产综合精品草原| 国产麻豆精品久久一二三| 久久99国产精品99久久| 国产伊人久久| 国产精品亚洲综合久久| 国产午夜免费高清久久影院| 四虎国产永久免费久久| 午夜精品久久久久久影视777| 国色天香久久久久久久小说| 久久国产色AV免费观看| 一本大道久久a久久精品综合| 无码任你躁久久久久久| 精品久久久无码21p发布| 狠狠色丁香久久综合婷婷| 欧美一级久久久久久久大片| 亚洲国产另类久久久精品小说| 国产精品一区二区久久精品| 久久精品亚洲乱码伦伦中文| 伊色综合久久之综合久久| 九九久久99综合一区二区| 香蕉aa三级久久毛片| 亚洲国产精品一区二区久久| 色8激情欧美成人久久综合电| 亚洲va久久久噜噜噜久久狠狠| 国产精品久久久久久久午夜片| 一级女性全黄久久生活片免费| 精品国产VA久久久久久久冰| 日本高清无卡码一区二区久久 | 无码人妻久久一区二区三区|