windows RPC 编程总结

idl文件ildTest1.idl:

import "oaidl.idl";
import "ocidl.idl";

[
  uuid(A112A4B2-3CA5-475c-B9C0-8684DBEBED52),
  version(1.0)
]
interface hw // The interface is named hw
{
   // A function that takes a zero-terminated string.
   void Hello(
      [in, string] const char* szOutput);
}


服务器端:

#include"stdafx.h"
#include
#include
#include"ildTest1_h.h"
#pragma comment(lib,"rpcrt4")
#pragma comment(lib,"ole32")
/*extern "C"{*/
	void Hello(handle_t IDL_handle,const unsigned char*psz){
		printf("server:%s\n",psz);
	}
	void Shutdown(handle_t IDL_handle){
		RpcMgmtStopServerListening(NULL);
		RpcServerUnregisterIf(NULL,NULL,FALSE);
	}
	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);
	}
/*}*/
int main()
{
	RPC_STATUS status;
	status = RpcServerUseProtseqEp(
		(RPC_CSTR)("ncacn_ip_tcp"), // Use TCP/IP protocol.

		RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // Backlog queue length for TCP/IP.

		(RPC_CSTR)("13521"), // TCP/IP port to use.

		NULL); // No security.

	if (status){
		printf("ServerUse failed\n");
		exit(status);}
	else printf("UseProtseqEq ok\n");
// 	status = RpcServerRegisterIf(
// 		hw_v1_0_s_ifspec, // Interface to register.
// 
// 		NULL, // Use the MIDL generated entry-point vector.
// 
// 		NULL);// Use the MIDL generated entry-point vector.

	// 注意:从Windows XP SP2 开始,增强了安全性的要求,如果用 RpcServerRegisterIf() 注册
	// 接口,客户端调用时会出现 RpcExceptionCode() == 5,即Access Denied 的错误. 因此,必
	// 须用 RpcServerRegisterIfEx 带 RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH 标志允许客户端直
	// 接调用。

	// RpcServerRegisterIf(HelloWorld_v1_0_s_ifspec, NULL, NULL);
	RpcServerRegisterIfEx(
		hw_v1_0_s_ifspec, // Interface to register.
		NULL,
		NULL, // Use the MIDL generated entry-point vector.
		RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
		RPC_C_LISTEN_MAX_CALLS_DEFAULT,
		NULL);

	if (status){
		printf("Register failed\n");
		exit(status);}
	else printf("Register if ok\n");
	// This call will not return until

	// RpcMgmtStopServerListening is called.

	status = RpcServerListen(
		1, // Recommended minimum number of threads.

		RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Recommended maximum number of threads.

		FALSE); // Start listening now.

	if (status){
		printf("Server listen failed\n");
		exit(status);}
	else printf("listen ok\n");
	return 0;
}


客户端:

#include "stdafx.h"
#include
#include
#include"ildTest1_h.h"
#pragma comment(lib,"rpcrt4")
#pragma comment(lib,"ole32")
int main(void){
	RPC_STATUS status;
	RPC_BINDING_HANDLE hwBinding;
	unsigned char* szStringBinding=NULL;
	status=RpcStringBindingCompose(//建立一个String Binding句柄,并不连接

		NULL,
		(RPC_CSTR)("ncacn_ip_tcp"),
		(RPC_CSTR)("localhost"),
		(RPC_CSTR)("13521"),
		NULL,
		(RPC_CSTR*)&szStringBinding); 
	if(status){
		printf("StringBinding failed\n");
		exit(status);}
	printf("szString=%s\n",szStringBinding);
	status=RpcBindingFromStringBinding(
		szStringBinding,
		&hwBinding);
	if(status){
		printf("Bind from String failed:%d\n",GetLastError());
		exit(status);}
	RpcTryExcept{
		Hello(hwBinding,(RPC_CSTR)("Hello RPC World!"));
	}
	RpcExcept(1){
		printf("Runtime reported exception:%d,except=%d\n",GetLastError(),RpcExceptionCode()/*RPC_S_ACCESS_DENIED==5L*/);//这里返回了5

	}
	RpcEndExcept
	status = RpcBindingFree(&hwBinding); // Frees the binding handle.
	RpcStringFree(&szStringBinding);
	

	if (status){
		printf("Bind free failed\n");
		exit(status);}
	return 0;
}
void* __RPC_USER midl_user_allocate(size_t size){
	return malloc(size);
}
// Memory deallocation function for RPC.

void __RPC_USER midl_user_free(void* p){
	free(p);
}


总结以及遇到的问题:

1)idl文件单独建立一个工程进行编译,不要在客户端或者服务器工程中编译,因为每次编译都会有所改变,而比如在客户端上包含了idl则会每次重新编译idl文件导致客户端和服务端对应文件不统一。(idlTest1_h.h 和 idlTest1_c.c在客户端中使用,ildTest1_h.h 和 ildTest1_s.c在服务器端使用)


以下段落为转载:

这节我们来谈谈 Windows NT 下 RPC 的高性能模式 - LPC。

很多 Windows 编程入门的书里面讲 Windows 的进程间通信,都会讲 WM_COPYDATA,讲匿名管道,讲命名管道,讲共享内存等等,
但是很少有讲 RPC 的,为什么呢?因为 RPC 看名字,就叫“Remote Procedure Call”,一看就是给分布式系统通信用的,虽然
也可以作为本机进程间通信用,但是性能上总是让人怀疑。所以很多人设计的进程间通信模型,都是用 WM_COPYDATA,或者管道,
或者干脆共享内存,相当于自己造轮子,一切从头做起。但 RPC 确实好用啊,调用起来就像调用库函数一样,通信的细节全给你
封装起来了。那 RPC 有没有性能好一点的模式呢?这就是下面要讲的 LPC 模式了。

LPC(Local Procedure Call)是 Windows NT 内部的高性能的通信模式。它是在内核中实现的,主要用于 Win32 子系统内部的
通信,比如 csrss, lsass 都大量的用到了 LPC。在前面演示的代码中,只需要改一行代码,我们就可使用 LPC 了,其实 RPC 就
是内部使用 LPC 来进行通信,性能大大提高。

服务端代码:
server.c
--------------
// 用LPC 方式通信
RpcServerUseProtseqEp(
    (unsigned char *)"ncalrpc",
    RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
    (unsigned char *)"AppName",
    NULL);


客户端代码:
client.c
--------------
// 用LPC 方式通信
// 第3 个参数NetworkAddr 只能取NULL
RpcStringBindingCompose(
    NULL,
    (unsigned char*)"ncalrpc",
    NULL, (unsigned char*)"AppName",
    NULL,
    &pszStringBinding );

你可能感兴趣的:(windows,rpc)