• <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的學習園地

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

              C++博客 :: 首頁 :: 新隨筆 ::  ::  :: 管理 ::

            前面簡單寫了點靜態結構,這一次將主要關注動態模型以及調用方式。

            這個系列的名字叫“為C++實現一個IDL”,實際上應該叫“為C++實現一個Remoting”可能更好一些,說是IDL,主要是想通過宏,使用簡單的類型定義達到自動生成調用代碼的目的。

            一、首先來看看調用習慣。

            從調用習慣入手,主要是因為看到目前有很多庫/工具包在調用上都有很多不便之處。假如能在一開始就從這點出發,就能把調用接口設計得更好一些。

            先來看看服務端如何開放一個服務。

            int?main?()
            {
            ????
            //?發布為SOAP服務,先生成一個服務容器。
            ????
            //?服務將發布在localhost的7911上,localhost用來綁定loopback網卡。
            ????SOAPProxy?soap_service?(7911,?“localhost”);

            ????TestService?test_service;?
            ????soap_service.addService??(“test_service”,?
            &test_service);

            ????TestService?service1;
            ????soap_service.addService?(“HelloService”,?
            &service1);

            ????
            try{
            ????????soap_service.run?();
            ????}?
            catch?(SocketException&?e)
            ????{
            ????}?
            catch?(SignalException&?e)
            ????{
            ????}

            ????
            return?0;
            }


            我希望就是這么簡單,客戶端調用有多種方式:
            1、?使用服務的IDL定義,直接調用:

            int?main?()
            {
            ????SOAPProxy?soap_service?(
            7911,?“localhost”);

            ????
            try{
            ????????TestService?test_service?(“test_service”,?
            &soap_service);
            ????????test_service.method1?(
            /**/);
            ????}?
            catch?(SocketException&?e)
            ????{
            ????}
            ????
            return?0;
            }


            這種方式比較簡單,調用時會檢查是否已經連接,然后發送調用請求,并處理調用結果。

            2、?服務驗證方式:

            int?main?()
            {
            ????SOAPProxy?soap_service?(
            7911,?“localhost”);
            ????TestService?test_service;
            ????soap_service.getService?(“test_service”,?
            &test_service);

            ????
            if?(test_service)
            ????{
            ????????
            try{
            ????????????test_service.method1?(
            /**/);
            ????????}?
            catch?(SocketException&?e)
            ????????{
            ????????}
            ????}
            ????
            return?0;
            }


            3、?服務發現方式:

            int?main?()
            {
            ????SOAPProxy?soap_service?(
            7911,?“localhost”);
            ????vector?
            <string>?services_name?=?soap_service.getServiceNames?();
            ????
            //?
            ????IService*?test_service?=?soap_service.getService?(“test_service”);
            ????
            if?(test_service)
            ????{
            ????????vector?
            <string>?methods?=?test_service->getMethodNames?();
            ????????IMethod
            *?method?=?test_service->getMethod?(“method1”);
            ????????vector?
            <Type*>?types?=?method->getParameterType?s()
            ????????method
            ->addArg?(3);
            ????????method
            ->addArg?(4);
            ????????
            //?
            ????????method->invoke?();
            ????????
            //?
            ????}
            ????
            return?0;
            }


            二、基本需求。

            簡單分析一下,上面一共涉及了哪些類型?
            IProxy:
            這是所有Proxy類的基類(和接口),它可以容納多個服務對象,提供服務綁定、服務查詢、服務發現、服務驗證。
            IService:
            所有Service類的基類,可以容納多個方法(Method),提供方法查詢、服務驗證。
            IMethod:
            所有Method模板類的基類,容納多個參數,包括返回值,可通過查詢參數類型獲得方法的類型定義。
            IParameter:
            所有參數的基類,包含一個參數類型描述和一個參數值。
            IType:
            所有類型的基類,預定義了一些基本類型,可自定義類型。

            看起來挺多的,其實很難接觸到這些,只需要使用宏來定義一個服務,就可以通過模板的類型推導,自動生成這些復雜的定義。

            三、調用過程。

            以下只簡單分析一下同步調用,異步調用將是以后的擴充話題。
            根據第二節的3種不同調用過程,簡要描述如下:
            1. 直接調用。

              • 生成SOAPProxy,讓它連接到遠程主機。
              • 生成一個TestService對象,設置遠程主機上的服務名稱,并指定使用SOAPProxy,也即使用SOAP協議。
              • 調用TestService::method1方法。根據method1的定義,把服務名稱、方法名稱、各個in參數等打包成一個“集合”,交給SOAPProxy處理。
              • SOAPProxy把這個“集合”轉換成SOAP消息,發送到遠程主機,阻塞線程。
              • 遠程主機上的SOAPProxy對象收到數據,進行解析。當解析出一個服務調用時,把它交給TestService服務處理。
              • TestService解析出一個方法調用,把它交給Method處理。
              • Method解析出各個參數,驗證參數類型、完整性等,并執行調用或返回錯誤。
              • Method調用的返回信息(包括調用結果、返回值、out參數等)被打包成一個“集合”,交給TestService處理。
              • TestService處理后,交給SOAPProxy。
              • SOAPProxy把結果打包成SOAP消息,發回調用端。
              • 調用端解析SOAP消息,把OUT參數值賦給調用者提供的對象,調用完成。

              ?

            2. 服務驗證方式。
              • 生成SOAPProxy,讓它連接到遠程主機。
              • 生成TestService對象,調用SOAPProxy的getService驗證版本。
              • SOAPProxy把TestService對象的信息(名稱、成員及基類型等)發送到遠程主機,阻塞。
              • 遠程主機解析收到的信息,查找服務名,并比較查找到的服務類型與解析得到的類型。
              • 比較結果發回給調用端。
              • 調用端接著采用直接調用的方式,調用遠程服務。

              這種方式看起來多了一些操作,不過驗證的好處是能夠減少調用時的異常。

            3. 服務發現方式。
              • 生成SOAPProxy,讓它連接到遠程主機。
              • 查詢遠程開放的服務名稱。(可省略)
              • 查找特定服務,得到服務描述信息。
              • 查找服務中的方法,得到方法描述信息。
              • 壓入各個參數,并執行調用。
              • 調用前先判斷參數是否與描述一致,然后調用SOAPProxy生成SOAP消息,發送到遠程主機,阻塞。
              • 遠程主機解析出調用。。。后面過程與第1種方式相同,遠程主機并不知道客戶端使用的是哪種方式來調用。遠程主機處理結束,將返回SOAP消息給調用端。
              • 調用端解析出調用結果,并把各個OUT參數的值賦給method對象。

              使用這種方式,調用端不需要服務的類型定義。

            四、異步調用/異步分派(AMI/AMD)。

            同步調用時,調用端線程需要等待調用結果,服務端線程也要等待調用結束返回,才處理下一個調用。
            為了在服務調用期間讓線程能做更多的事:
            調用端把調用交給線程池完成,并在調用完成后采用某種機制通知線程處理結果,或者直接由線程池中的調用線程調用結果處理函數。這種方式稱為AMI(異步方法調用)。
            服務端主線程則把接收到的消息解析后,放入處理隊列,由線程池去處理調用過程。當調用完成后,結果放入結果隊列,由主線程處理成消息,發送回調用端。這種方式稱為AMD(異步方法分派)。
            調用端和服務端依舊是使用通訊協議來溝通,雙方都不知道對方是否采用了異步方式。

            AMI和AMD對于靜態定義的服務是有影響的,比如下面一個服務:

            struct?TestService
            {
            ????Method?
            <void(in<int>,?out<int>)>?method1;
            }


            在同步調用時,它的調用方式:

            TestService?test_service;
            int?a;
            service.method1?(
            3,?a);?//?或者?service.method1?(3,?&a),打算兼容這2種方式。


            異步調用時,調用方式:

            void?method1_result?(int,?int);
            TestService?test_service;
            test_service.method1.async_call(
            3,?method1_result);?//?調用完成后,讓調用線程去調用method1_result通知調用結果。
            //?或者像下面
            IMethod*?result?=?test_service.method1.async_call?(3);
            while?(!result->done())??//?還有很多好辦法,這里只是為了簡單。
            {
            ????sleep?(
            1);
            }
            cout?
            <<?result->getArg(1)->toInt();?


            正如上面演示的一樣,異步調用的結果有2種方式去處理。
            一是由線程池調用完以后,接著調用一個函數以通知結果。它不需要輪詢,不過涉及到了線程問題,增加了一些復雜性。
            另一種方式調用結束后,原調用線程在某個適當的“時機”去查詢調用結果。這個時機可以是定時查詢,也可以是被線程消息通知而去處理。

            五、其它。

            這一篇加上前一篇,應該是提到了全部的要點。
            目前剩下的唯一一個難點,可能是在處理異步調用時,Method的定義。
            正如上面演示的,一個方法在同步調用和異步調用時,就有3種調用方式:

            service.method1?(3,?a);
            test_service.method1.async_call(
            3,?method1_result);
            IMethod
            *?result?=?test_service.method1.async_call?(3);


            特別地,它如何根據in和個數和out的個數,產生那2個參數個數匹配的異步調用函數?
            再來回顧一下method1的定義:

            Method?<void(in<int>,?out<int>)>?method1;


            顯然有一定的復雜性,不過我認為還是可以處理掉的。拿3個參數的偏特化版本來說明:

            template?<class?Ret,?class?A,?class?B,?class?C>
            class?Method?<Out<Ret>(A,B,C)>?:?public?MethodBase?<Out<Ret>,A,B,C>
            {
            };

            template?
            <class?Ret=NullType,?class?A=NullType,?class?B=NullType,?class?C=NullType,?class?D=NullType,?IN_COUNT=InCount<?A,B,C,D>::value?>
            class?MethodBase
            {
            };


            通過對MethodBase類的IN_COUNT參數定義偏特化,即可定義出這些不同的版本。

            當然僅僅是知道了IN參數的個數,還沒有提取出IN參數的類型,所以還不能生成函數的原型,或許需要把typelist加進來了(loki中的那個)。



            這是后面要考慮的內容,今天先想到這。

            posted on 2005-09-17 19:40 qiezi 閱讀(943) 評論(4)  編輯 收藏 引用 所屬分類: 自家破爛C++asgard項目
            中文字幕久久精品无码| 国产巨作麻豆欧美亚洲综合久久 | 色8激情欧美成人久久综合电| 一级做a爱片久久毛片| 久久久久亚洲AV综合波多野结衣 | 久久久久夜夜夜精品国产| 色噜噜狠狠先锋影音久久| 日韩一区二区久久久久久| 日日狠狠久久偷偷色综合免费| 精品久久久无码人妻中文字幕| 久久99精品国产自在现线小黄鸭| 99久久精品费精品国产| 久久久久亚洲精品日久生情| 亚洲狠狠久久综合一区77777| 欧美伊人久久大香线蕉综合 | 精品久久人人爽天天玩人人妻 | 国产精品美女久久久久网| 99久久国产亚洲高清观看2024 | 99精品久久精品一区二区| 久久精品麻豆日日躁夜夜躁| 久久久久综合中文字幕 | 少妇久久久久久被弄高潮| 情人伊人久久综合亚洲| 久久精品免费一区二区| 久久激情亚洲精品无码?V| 99re久久精品国产首页2020| 久久久久久国产精品美女 | 激情综合色综合久久综合| 无码伊人66久久大杳蕉网站谷歌 | 色婷婷综合久久久久中文一区二区| 成人亚洲欧美久久久久| 7777久久亚洲中文字幕| 久久精品亚洲AV久久久无码| 日本高清无卡码一区二区久久| 国产日产久久高清欧美一区| 无码久久精品国产亚洲Av影片 | 国产成人精品久久一区二区三区av| 国产偷久久久精品专区 | 国产精品久久久久久久午夜片 | 青青草国产精品久久久久| 国产91色综合久久免费|