• <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>
            隨筆 - 60, 文章 - 0, 評(píng)論 - 197, 引用 - 0
            數(shù)據(jù)加載中……

            Win32 RPC 編程(一)

            我們從一個(gè)簡(jiǎn)單的 RPC “Hello, world!”的例子開(kāi)始。
            參考資料:MSDN: Win32 and COM Development -> Networking -> Network Protocols -> Remote Procedure Calls (RPC)


            第1步:編寫(xiě) IDL(Interface Description Language,接口描述語(yǔ)言)文件
            -------------------------------------------------------------------------
            IDL 是一個(gè)通用的工業(yè)標(biāo)準(zhǔn)語(yǔ)言,大家應(yīng)該不陌生,因?yàn)?COM 里面也是用它來(lái)描述接口的。
            Hello.idl:

            [
                 uuid("4556509F-618A-46CF-AB3D-ED736ED66477"),   // 唯一的UUID,用 GUIDGen 生成
                 version(1.0)
            ]

            interface HelloWorld 
            {
                 // 我們定義的方法
                 void Hello([in,string]const char * psz);
                 void Shutdown(void); 
            }


            一個(gè)可選的文件是應(yīng)用程序配置文件(.acf),它的作用是對(duì) RPC 接口進(jìn)行配置,例如下面的 Hello.acf 文件:
            Hello.acf:


                 implicit_handle(handle_t    HelloWorld_Binding) 


            interface HelloWorld
            {

            }

            上面定義了 implicit_handle,這樣客戶端將綁定句柄 HelloWorld_Binding 了,后面的客戶端代碼中我們會(huì)看到。


            編譯 IDL 文件:
            >midl Hello.idl
            Microsoft (R) 32b/64b MIDL Compiler Version 6.00.0366
            Copyright (c) Microsoft Corporation 1991-2002. All rights reserved.
            Processing .\Hello.idl
            Hello.idl
            Processing .\Hello.acf
            Hello.acf

             
            我們可以看到自動(dòng)生成了 Hello.h, Hello_s.c, Hello_c.c 文件,這些叫做 rpc stub 程序,不過(guò)我們可以不管這個(gè)概念,
            我們只需要知道 Hello.h 里面定義了一個(gè)

            extern RPC_IF_HANDLE HelloWorld_v1_0_s_ifspec;

            這個(gè) RPC_IF_HANDLE 將在后面用到。

             
            第2步:編寫(xiě)服務(wù)端程序
            -------------------------------------------------------------------------
            第1步中我們已經(jīng)約定了調(diào)用的接口,那么現(xiàn)在我們開(kāi)始實(shí)現(xiàn)其服務(wù)端。代碼如下:
            server.c

            #include <stdlib.h>
            #include <stdio.h>
            #include "Hello.h"     // 引用MIDL 生成的頭文件

            /**
             * 這是我們?cè)贗DL 中定義的接口方法
             * 需要注意一點(diǎn),IDL 里面的聲明是:void Hello([in,string]const char * psz);
             * 但是這里變成了const unsigned char *,為什么呢?
             * 參見(jiàn)MSDN 中的MIDL Command-Line Reference -> /char Switch
             * 默認(rèn)的編譯選項(xiàng),對(duì) IDL 中的char 按照unsigned char 處理
             */

            void Hello(const unsigned char * psz)
            {
                 printf("%s\n", psz);
            }

             
            /** 這也是我們?cè)贗DL 中定義的接口方法,提供關(guān)閉server 的機(jī)制*/
            void Shutdown(void)
            {
                 // 下面的操作將導(dǎo)致 RpcServerListen() 退出
                 RpcMgmtStopServerListening(NULL);
                 RpcServerUnregisterIf(NULL, NULL, FALSE);
            }

            int main(int argc,char * argv[])
            {
                 // 用Named Pipe 作為RPC 的通道,這樣EndPoint 參數(shù)就是Named Pipe 的名字
                 // 按照Named Pipe 的命名規(guī)范,\pipe\pipename,其中pipename 可以是除了\
                 // 之外的任意字符,那么這里用一個(gè)GUID 串來(lái)命名,可以保證不會(huì)重復(fù)
                 RpcServerUseProtseqEp((unsigned char *)"ncacn_np", 20, (unsigned char *)"\\pipe\\{8dd50205-3108-498f-96e8-dbc4ec074cf9}", NULL);   

                 // 注冊(cè)接口,HelloWorld_v1_0_s_ifspec 是在MIDL 生成的Hello.h 中定義的
                 RpcServerRegisterIf(HelloWorld_v1_0_s_ifspec, NULL, NULL);
               
                 // 開(kāi)始監(jiān)聽(tīng),本函數(shù)將一直阻塞
                 RpcServerListen(1,20,FALSE);
                 return 0;
            }

            // 下面的函數(shù)是為了滿足鏈接需要而寫(xiě)的,沒(méi)有的話會(huì)出現(xiàn)鏈接錯(cuò)誤
            void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
            {
                 return(malloc(len));
            }

            void __RPC_USER midl_user_free(void __RPC_FAR *ptr)
            {
                 free(ptr);
            }

             

            編譯:
            >cl /D_WIN32_WINNT=0x500 server.c Hello_s.c rpcrt4.lib
            用于 80x86 的 Microsoft (R) 32 位 C/C++ 優(yōu)化編譯器 14.00.50727.42 版
            版權(quán)所有(C) Microsoft Corporation。保留所有權(quán)利。

            server.c
            Hello_s.c
            正在生成代碼...
            Microsoft (R) Incremental Linker Version 8.00.50727.42
            Copyright (C) Microsoft Corporation.  All rights reserved.

            /out:server.exe
            server.obj
            Hello_s.obj
            rpcrt4.lib

            編譯時(shí)為什么要指定 _WIN32_WINNT=0x500 呢?因?yàn)槿绻麤](méi)有的話會(huì)報(bào)告下面的錯(cuò)誤:
            Hello_s.c(88) : fatal error C1189: #error :  You need a Windows 2000 or later to
            run this stub because it uses these features:

             
            第3步:編寫(xiě)客戶端程序
            -------------------------------------------------------------------------
            客戶端的代碼:
            client.c

            #include <stdlib.h>
            #include <stdio.h>
            #include <string.h>
            #include "Hello.h"     // 引用MIDL 生成的頭文件

            int main(int argc, char * argv[])
            {
                 unsigned char * pszStringBinding = NULL;
                 if ( argc != 2 )
                 {
                     printf("Usage:%s <Hello Text>\n", argv[0]);
                     return 1;
                 }   

                 // 用Named Pipe 作為RPC 的通道。參見(jiàn)server.c 中的RpcServerUseProtseqEp() 部分
                 // 第3 個(gè)參數(shù)NetworkAddr 如果取NULL,那么就是連接本機(jī)服務(wù)
                 // 否則要取\\\\servername 這樣的格式,例如你的計(jì)算機(jī)名為jack,那么就是\\jack
                 RpcStringBindingCompose( NULL, (unsigned char*)"ncacn_np", /*(unsigned char*)"\\\\servername"*/ NULL, (unsigned char*)"\\pipe\\{8dd50205-3108-498f-96e8-dbc4ec074cf9}", NULL, &pszStringBinding );

                 // 綁定接口,這里要和 Hello.acf 的配置一致,那么就是HelloWorld_Binding
                 RpcBindingFromStringBinding(pszStringBinding, & HelloWorld_Binding );   

                 // 下面是調(diào)用服務(wù)端的函數(shù)了
                 RpcTryExcept
                 {
                     if ( _stricmp(argv[1], "SHUTDOWN") == 0 )
                     {
                          Shutdown();
                     }
                     else
                     {
                          Hello((unsigned char*)argv[1]);
                     }
                 }
                 RpcExcept(1)
                 {
                     printf( "RPC Exception %d\n", RpcExceptionCode() );
                 }
                 RpcEndExcept

             
                 // 釋放資源
                 RpcStringFree(&pszStringBinding);
                 RpcBindingFree(&HelloWorld_Binding);
                 return 0;
            }

             
            // 下面的函數(shù)是為了滿足鏈接需要而寫(xiě)的,沒(méi)有的話會(huì)出現(xiàn)鏈接錯(cuò)誤
            void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
            {
                 return(malloc(len));
            }

            void __RPC_USER midl_user_free(void __RPC_FAR *ptr)
            {
                 free(ptr);
            }

             

            編譯:
            >cl /D_WIN32_WINNT=0x500 client.c Hello_c.c rpcrt4.lib
            用于 80x86 的 Microsoft (R) 32 位 C/C++ 優(yōu)化編譯器 14.00.50727.42 版
            版權(quán)所有(C) Microsoft Corporation。保留所有權(quán)利。

            client.c
            Hello_c.c
            正在生成代碼...
            Microsoft (R) Incremental Linker Version 8.00.50727.42
            Copyright (C) Microsoft Corporation.  All rights reserved.

            /out:client.exe
            client.obj
            Hello_c.obj
            rpcrt4.lib

             

            第4步:測(cè)試:
            -------------------------------------------------------------------------
            運(yùn)行 server.exe,將彈出一個(gè) console 窗口,等待客戶端調(diào)用。
            運(yùn)行客戶端 client.exe:

            >client hello
            可以看到 server.exe 的 console 窗口出現(xiàn) hello 的字符串。


            >client shutdown
            server.exe 退出。

            示例下載
             

            posted on 2008-04-28 18:50 Normandy 閱讀(23001) 評(píng)論(16)  編輯 收藏 引用 所屬分類: Networking

            評(píng)論

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            你好,你的Win32 RPC 編程(一)讓我對(duì)Windows RPC編程有了一個(gè)很形象地認(rèn)識(shí),非常感謝。不過(guò)我在用你的代碼做實(shí)驗(yàn)時(shí)發(fā)現(xiàn)編譯有些問(wèn)題,之今不知道為什么。還望賜教。

            我用2005新建了一個(gè)c++ Console Application,然后按照你的順序,依次新建了Hello.idl和Hello.acf文件,編譯后,的確看到生成出來(lái)的Hello_c.c,Hello_h.h和Hello_s.c,但在Solution Explorer中看不到這些生成出來(lái)的文件。接著我復(fù)制完服務(wù)端程序后編譯后,出現(xiàn)下列錯(cuò)誤:
            1>RPCServer.obj : error LNK2019: unresolved external symbol __imp__RpcServerUnregisterIf@12 referenced in function _Shutdown
            1>RPCServer.obj : error LNK2019: unresolved external symbol __imp__RpcMgmtStopServerListening@4 referenced in function _Shutdown
            1>RPCServer.obj : error LNK2019: unresolved external symbol __imp__RpcServerListen@12 referenced in function _wmain
            1>RPCServer.obj : error LNK2019: unresolved external symbol __imp__RpcServerRegisterIf@12 referenced in function _wmain
            1>RPCServer.obj : error LNK2001: unresolved external symbol _HelloWorld_v1_0_s_ifspec
            1>RPCServer.obj : error LNK2019: unresolved external symbol __imp__RpcServerUseProtseqEpW@16 referenced in function _wmain

            如果我將那幾個(gè)生成出來(lái)的文件手動(dòng)加入到Solution Explore中后,編譯后報(bào)下列錯(cuò)誤:

            1>Hello_s.c
            1>c:\zhongwei\rpc\rpcserver\rpcserver\hello_s.c(226) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
            1>Hello_c.c
            1>c:\zhongwei\rpc\rpcserver\rpcserver\hello_c.c(225) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?

            你能知道是什么原因造成的么?
            2008-10-19 13:56 | 金中偉

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            我的EMAIL:juniorzhong@gmail.com
            MSN:junior_zhong@tom.com

            期待你的指點(diǎn),謝謝!
            2008-10-19 14:08 | 金中偉

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            @金中偉
            其實(shí)沒(méi)有這么復(fù)雜,我是通過(guò) Makefile 編譯的, 沒(méi)有用 IDE。你打開(kāi) Visual Studio 2005 Command Prompt 或 Visual Studio 2008 Command Prompt ,然后進(jìn)到源碼目錄下 敲一個(gè) nmake 命令, 所有的都會(huì)為你自動(dòng)生成。細(xì)節(jié)可查看源碼目錄下的 Makefile 文件。
            2008-10-20 10:09 | Normandy

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            @金中偉
            你出錯(cuò)的原因貌似是有些函數(shù)庫(kù)沒(méi)有添加到引用中,所以編譯時(shí)有無(wú)法解析的標(biāo)志錯(cuò)誤。或者跟工程編碼有關(guān),自己察看下吧
            2009-08-03 18:17 | qb

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            你的問(wèn)題是沒(méi)有添加RPC Runtime Library,你可以在工程屬性的'連接器'下的輸入 添加'附加依賴項(xiàng)' Rpcrt4.lib,或者在你的CPP文件開(kāi)頭添加如下語(yǔ)句
            #pragma comment(lib, "Rpcrt4.lib")
            2009-08-24 23:15 | Quincy, Hu

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            RPC 學(xué)好了,大有用處。
            2009-10-14 21:49 | jc_ontheroad

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            問(wèn)下大家,在windows下編譯器cl.exe 用/I來(lái)說(shuō)明頭文件的路徑,用什么參數(shù)來(lái)說(shuō)明庫(kù)文件的路徑啊?
            2011-04-27 08:03 | liweihua

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            @liweihua
            /LIBPATH:"X:\xxx\xxx"
            2011-04-27 09:28 | 溪流

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            windows下有沒(méi)有像RPCGEN這樣的工具啊?
            2011-08-24 16:38 | tal

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            呵呵,樓主,感謝你的文章啊。
            我也喜歡用命令行編譯程序。呵呵
            2012-05-25 15:16 | 憑凡

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            我在2010編譯的。結(jié)果是1714結(jié)果,
            服務(wù)器起不來(lái)
            2012-09-03 14:23 | 董香升

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            我把程序改成相應(yīng)的wchar_t的unicode版本。可是server.cpp中RpcServerUseProtseqEp返回1703號(hào)錯(cuò)誤。找不到愿意,希望指點(diǎn)一下。我在開(kāi)頭#define UNICODE了。
            2012-09-04 11:31 |

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            我把程序改成相應(yīng)的wchar_t的unicode版本。可是server.cpp中RpcServerUseProtseqEp返回1703號(hào)錯(cuò)誤。找不到愿意,希望指點(diǎn)一下。我在開(kāi)頭#define UNICODE了。
            2012-09-04 11:32 | 董香升

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            請(qǐng)教原因和解決方法:
            網(wǎng)上獲取RPC實(shí)例,比如http://blog.163.com/junior_zhong/blog/static/27871180200891810561138/
            在main()中的:
            status = RpcServerUseProtseqEp(
            reinterpret_cast <unsigned char*>("ncacn_np"),
            nMaxCalls,
            reinterpret_cast <unsigned char*>("//pipe//{a5194558-21a6-4978-9610-2072fcf1dc6e}"),
            NULL );

            編譯時(shí)出現(xiàn)錯(cuò)誤:
            error C2664: 'RpcServerUseProtseqEpW' : cannot convert parameter 1 from 'unsigned char *' to 'RPC_WSTR'
            按照網(wǎng)上方法,reinterpret_cast <unsigned char*>可以解決兩個(gè)字符串問(wèn)題,但是不能搞定最后一個(gè)參數(shù)NULL一直報(bào)錯(cuò)C2664。
            2012-09-06 14:34 | iHyy

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            @董香升
            請(qǐng)問(wèn)后來(lái)怎么解決的啊?
            2015-07-13 15:58 | 范范

            # re: Win32 RPC 編程(一)  回復(fù)  更多評(píng)論   

            如果你沒(méi)有使用Makefile編譯而是采用vs的屬性中配置來(lái)編譯,server.cpp中RpcServerUseProtseqEp返回1703號(hào)錯(cuò)誤, 或是RpcServerListen報(bào)錯(cuò)。請(qǐng)?jiān)趯傩皂?yè)->常規(guī)->字符集中選擇未設(shè)置,也就是disable UNICODE
            2016-02-17 13:55 | zhang_luo@qq.com
            久久久久久久波多野结衣高潮| 久久天天躁狠狠躁夜夜2020一 | 久久99国产精品尤物| 国产成人综合久久精品红 | 久久中文字幕无码专区| 久久精品水蜜桃av综合天堂| 久久久网中文字幕| 国产免费福利体检区久久| 成人综合伊人五月婷久久| 色欲综合久久中文字幕网| 亚洲人成无码www久久久| 久久久久久噜噜精品免费直播| 久久国产亚洲精品无码| 久久精品国产精品亚洲精品| 久久久久综合国产欧美一区二区| 97久久精品人妻人人搡人人玩| 97视频久久久| 亚洲国产另类久久久精品小说| 亚洲午夜精品久久久久久浪潮 | 日本欧美久久久久免费播放网| 中文字幕无码免费久久| 精品久久无码中文字幕| 狠狠久久亚洲欧美专区 | 久久精品国产国产精品四凭| 久久久久国产成人精品亚洲午夜| 久久乐国产精品亚洲综合| 2020国产成人久久精品| 久久夜色精品国产噜噜麻豆| AAA级久久久精品无码片| 超级碰久久免费公开视频| 午夜精品久久久久9999高清| 性做久久久久久久久浪潮| 久久久久99精品成人片欧美| 国产精品成人99久久久久 | 精品国产热久久久福利| 久久强奷乱码老熟女网站 | 国产精品美女久久久m| 久久国产精品二国产精品| 久久久久亚洲精品日久生情| 狠狠色丁香婷婷久久综合不卡 | 无码AV中文字幕久久专区|