RPC overviews-2

文章目录

  • 5. 讲解
    • 5.1 独立应用程序
    • 5.2 定义界面
    • 5.3 生成UUID
    • 5.4 IDL文件
    • 5.5 ACF文件
    • 5.6 生成存根文件
    • 5.7 客户端
    • 5.8 服务器
    • 5.9 停止服务器应用程序
    • 5.10 编译与链接
    • 5.11 运行应用程序

5. 讲解

针对3、4节进行补充讲解

5.1 独立应用程序

5.2 定义界面

5.3 生成UUID

idl中的版本号可确保当RPC接口有多个版本时,仅连接客户端和服务器的兼容版本。

5.4 IDL文件

//file hello.idl
[
	uuid(7A385E9F-A4F9-4F6D-AD2E-E155AB618471),
	version(1.0)
]
interface hello
{
	void HelloProc([in, string] unsigned char * pszString);
	void Shutdown(void);
}

[string]属性指定存根应该把参数作为C风格的字符串。

客户端应用程序应该能够关闭服务器应用程序,因此该接口包含另一个远程功能Shutdown的原型,该原型将在本教程的后面部分实现。

5.5 ACF文件

ACF标头中的[ implicit_handle]属性允许客户端应用程序为其远程过程调用选择服务器。ACF将句柄定义为handle_t类型(MIDL基本数据类型)。MIDL编译器会将ACF指定的绑定句柄名称hello_IfHandle放入它生成的头文件中。

5.6 生成存根文件

确保Hello.idl和Hello.acf位于同一目录中。以下命令将生成头文件Hello.h,以及客户端和服务器存根Hello_c.c, Hello_s.c

midl hello.idl

hello.h重要定义:

void HelloProc( 
    /* [string][in] */ unsigned char *pszString);

void Shutdown( void);


extern handle_t hello_IfHandle;

extern RPC_IF_HANDLE hello_v1_0_c_ifspec;
extern RPC_IF_HANDLE hello_v1_0_s_ifspec;

void  * __RPC_USER MIDL_user_allocate( _In_ size_t size);
void  __RPC_USER MIDL_user_free( _Pre_maybenull_ _Post_invalid_ void  * );

不需要对存根文件两个.c文件进行任何操作。

5.7 客户端

ncacn_np协议序列对应管道名"\\pipe\\pipename."

#include 
#include "hello_h.h" 

#pragma comment(lib, "rpcrt4.lib")

int main()
{
	RPC_STATUS status;
	unsigned char * pszUuid = NULL;
	unsigned char * pszProtocolSequence = (unsigned char *)"ncalrpc";
	unsigned char * pszNetworkAddress = NULL;
	unsigned char * pszEndpoint = (unsigned char *)"12888";
	unsigned char * pszOptions = NULL;
	unsigned char * pszStringBinding = NULL;
	unsigned char * pszString = (unsigned char *)"hello, world";
	unsigned long ulCode;

	status = RpcStringBindingComposeA(pszUuid,
		pszProtocolSequence,
		pszNetworkAddress,
		pszEndpoint,
		pszOptions,
		&pszStringBinding);
	if (status) exit(status);

	status = RpcBindingFromStringBinding(pszStringBinding, &hello_IfHandle);

	if (status) exit(status);

	RpcTryExcept
	{
		HelloProc(pszString);
		getchar();
		Shutdown();
	}
		RpcExcept(1)
	{
		ulCode = RpcExceptionCode();
		printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
	}
	RpcEndExcept

	status = RpcStringFree(&pszStringBinding);

	if (status) exit(status);

	status = RpcBindingFree(&hello_IfHandle);

	if (status) exit(status);

	return 0;
}

/******************************************************/
/*         MIDL allocate and free                     */
/******************************************************/

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);
}

5.8 服务器

#include 

#include "hello_h.h"

#pragma comment(lib, "rpcrt4.lib")

int main()
{
	RPC_STATUS status;
	unsigned char * pszProtocolSequence = (unsigned char *)"ncalrpc";
	unsigned char * pszEndpoint = (unsigned char *)"12888";
	unsigned char * pszSecurity = NULL;
	unsigned int    cMinCalls = 1;
	unsigned int    fDontWait = FALSE;

	status = RpcServerUseProtseqEp(
		pszProtocolSequence, 
		RPC_C_LISTEN_MAX_CALLS_DEFAULT,
		pszEndpoint,
		pszSecurity);
	if (status) exit(status);

	status = RpcServerRegisterIf(
		hello_v1_0_s_ifspec,
		NULL,
		NULL);
	if (status) exit(status);

	status = RpcServerListen(
		cMinCalls,
		RPC_C_LISTEN_MAX_CALLS_DEFAULT,
		fDontWait
		);
	if (status) exit(status);


	return 0;
}

void HelloProc(unsigned char * pszString)
{
	printf("%s\n", pszString);
}

/* add this function to hellop.c */
void Shutdown(void)
{
	RPC_STATUS status;

	status = RpcMgmtStopServerListening(NULL);

	if (status)
	{
		exit(status);
	}

	status = RpcServerUnregisterIf(
		NULL, // unregister all 
		NULL, // interfaces
		FALSE);	// interface should be removed from the registry immediately, dont't wait for pending

	if (status)
	{
		exit(status);
	}
} //end Shutdown

/******************************************************/
/*         MIDL allocate and free                     */
/******************************************************/
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);
}

5.9 停止服务器应用程序

停止侦听客户端的两种方法:

  • RpcMgmtStopServerListening + RpcServerUnregisterIf
  • 退出主机

RpcServerListen直到发生异常或调用RpcMgmtStopServerListening才会停止,默认只有另一台服务器的线程才能调用RpcMgmtStopServerListening来停止一台服务器。客户端若调用则会返回RPC_S_ACCESS_DENIED,但服务端通过RpcMgmtSetAuthorizationFn 可以授权客户端停止服务。

5.10 编译与链接

msdn上用的makefile。

5.11 运行应用程序

你可能感兴趣的:(windows)