• Bidirectional RPC


    Sample Image - birpc.jpg

    Introduction

    RPC is frequently not used directly, so, usually you don't have to know the RPC API when you are using DCOM to communicate between systems on the www. But - as you will see later - there are times when the un-cover RPC is very useful.

    For instance: In the conventional RPC programming, you have two pieces of software, each in distinguishable executable form.

    Collapse Copy Code
    app A : the client - send request to be served.
    app B : the server - complies to the client request.

    This is nice and satisfactory most of the time. But, for getting this goal - you don't need to use the RPC directly- the distributed COM is more than enough.

    So, when do you really need the RPC?

    Well, suppose that one executable plays the role of either the client or the server, alternatively. Beyond that, suppose that the client-role and the server-role use the same interface and the same functions.

    Confused?

    Don't be !!!

    The solution

    1. Try the downloaded demo project and scan carefully the source code for further information...
    2. Read the following lines before the great trial:

    Explanation

    I assume you already know how to produce the RPC code by the MIDL compiler, so I'll explain just the changes needed to be done:

    1. Some variables in the RPC code have to be replaced by similar variables so there will not be duplicated variables because the client and the server code use similar names for three variables.
      Collapse Copy Code
       __MIDL_ProcFormatString replaced by __MIDL_ProcFormatString2
          __MIDL_TypeFormatString replaced by  __MIDL_TypeFormatString2
          <interface_name>_StubDesc replaced by <interface_name>_StubDesc2

      The changes above should be done just in the client side of the source code.

      We can't use one instance of those variables for the client and the server side, because in each situation those variables have different values;

    2. Add all the files needed to be involved in the RPC story, in one project, rather than while the RPC is regular implemented - in two different projects.
    3. Also, change the name of the functions involved in the RPC story:
      Collapse Copy Code
        <func-name>(<parameters>) to <func-name>2(<parameters>).

      This is a snippet code from the demo project. The server side interface implements the GetName function. Because both the client side and the server side implements the following function:

      Collapse Copy Code
         void GetName(
          /* [size_is][string][out] */ unsigned char __RPC_FAR name[  ])
          {
          ....
          }
          

      ...and because we compiled together the client and the server code, we have to change the func-name in the server side to avoid duplication, as follows:

      Collapse Copy Code
         void GetName2(
          /* [size_is][string][out] */ unsigned char __RPC_FAR name[  ])
          {
          ....
          }

      This is the function generated by MIDL - the one and only change is the name of the internal function GetName (the pure implementation func - stub naked).

      Collapse Copy Code
      void __RPC_STUB
          details_GetName(
          PRPC_MESSAGE _pRpcMessage )
          {
          MIDL_STUB_MESSAGE _StubMsg;
          unsigned char ( __RPC_FAR *name )[  ];
          RPC_STATUS _Status;
          ((void)(_Status));
          NdrServerInitializeNew(
          _pRpcMessage,
          &_StubMsg,
          &details_StubDesc);
          name = 0;
          RpcTryFinally
          {
          RpcTryExcept
          {
          if(_StubMsg.Buffer > _StubMsg.BufferEnd)
          {
          RpcRaiseException(RPC_X_BAD_STUB_DATA);
          }
          }
          RpcExcept( RPC_BAD_STUB_DATA_EXCEPTION_FILTER )
          {
          RpcRaiseException(RPC_X_BAD_STUB_DATA);
          }
          RpcEndExcept
          if(100 * 1 < 0)
          {
          RpcRaiseException(RPC_X_INVALID_BOUND);
          }
          name = (unsigned char (*)[])NdrAllocate(&_StubMsg,100 * 1);
          // GetName(*name) is the original source line produced
                  // by midl compiler.
                  GetName2(*name);
          _StubMsg.BufferLength = 0U;
          _StubMsg.MaxCount = 100;
          NdrConformantStringBufferSize(
          (PMIDL_STUB_MESSAGE) &_StubMsg,
          (unsigned char __RPC_FAR *)*name,
          (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[2] );
          _pRpcMessage->BufferLength = _StubMsg.BufferLength;
          _Status = I_RpcGetBuffer( _pRpcMessage );
          if ( _Status )
          RpcRaiseException( _Status );
          _StubMsg.Buffer =
          (unsigned char __RPC_FAR *) _pRpcMessage->Buffer;
          _StubMsg.MaxCount = 100;
          NdrConformantStringMarshall(
          (PMIDL_STUB_MESSAGE)& _StubMsg,
          (unsigned char __RPC_FAR *)*name,
          (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[2] );
          }
          RpcFinally
          {
          if ( name )
          _StubMsg.pfnFree( name );
          }
          RpcEndFinally
          _pRpcMessage->BufferLength =
          (unsigned int)((long)_StubMsg.Buffer -
          (long)_pRpcMessage->Buffer);
          }

    Practice

    To test the demo-project, launch two copies of the GETNAME application. In any copy type two distinguish end points, and your name against your enemy's name (or your wife - ditto).

    Collapse Copy Code
             end point of    end point of     your name
    remote server   local server
    ---------------  -------------    ------------
    app A -   55459            55460            moshe
    app B -   55460            55459            shoshana

    Click on PlayServer button on both copies. As you can see, each application points to the other application, so the communication is bi-directional. Thus each application is both the client and the server, with the same request (i.e. - get the name from the remote application).

    The IP in this demo, represented by 'localhost' string, points to the local computer, represented by 'localhost'.

    Click on 'get name from remote server' button - in each copy of the application, and you will get the name of the opposite application's user.

    Bravo !!!

    Compatibility note

    The demo project works well in Windows 98 and Windows 2000.

    Clarification

    To make it simple and to highlight the topic of this article, I didn't use some necessary code (RPC exception, thread's status checking of activities from cradle to garden of Eden and other useful status handling).

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    About the Author

    moshe masas


    I'm just a small brain connected to an un-limited
    brains network, which lead directly to the top ten
    giant minds. Which lead me to the
    thought : who am i?

    I am just a jerry-built god !
    Occupation: Web Developer
    Location: Israel Israel
  • 相关阅读:
    材料用词积累
    SqlServer 数据库/数据表 拆分(分布式)【转】
    SqlServer 数据库读写分离【转】
    (整理)在REHL6.5上部署ASP.NET MVC
    (整理)MySQL_REHL6.5 安装MySQL5.5
    (转)查看SQLServer最耗资源时间的SQL语句
    (转)SQLServer查询数据库各种历史记录
    (转)SqlServer2008 数据库同步:发布、订阅
    (整理)SQL Server 2008 CDC 功能使用
    (整理)EF分页的实现
  • 原文地址:https://www.cnblogs.com/adylee/p/1339715.html
Copyright © 2020-2023  润新知