Window RPC 详细运用

前言

         Thrift是一款由Fackbook开发的可伸缩、跨语言的服务开发框架,该框架已经开源并且加入的Apache项目。Thrift主要功能是:通过自定义的Interface Definition Language(IDL),可以创建基于RPC的客户端和服务端的服务代码,本来是准备研究下Thrift跨语言RPC框架,为了预预热想先总结下Window RPC的开发经验,下一期发布我学习Thrift框架的开发经验。

          Window 系统下要做RPC通讯,需要先编idl文件,先制作一个基础类型文件ms-dtyp.idl,内容如下

cpp_quote("#ifndef _DTYP_IDL")
cpp_quote("#define _DTYP_IDL")

/* Common data types */
cpp_quote("#ifndef _WINDEF_H")
typedef int BOOL, *PBOOL, *LPBOOL;
typedef unsigned char BYTE, *PBYTE, *LPBYTE;
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
cpp_quote("#endif")
cpp_quote("#ifndef _BASETSD_H_")
typedef unsigned int DWORD32;
typedef unsigned __int64 DWORD64;
cpp_quote("#endif")
//typedef unsigned long error_status_t;
cpp_quote("#ifndef _WINDEF_H")
typedef int INT, *LPINT;
cpp_quote("#endif")
cpp_quote("#ifndef _BASETSD_H_")
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
typedef signed __int64 INT64;
cpp_quote("#endif")
cpp_quote("#ifndef _BASETSD_H_")
typedef signed int LONG32;
typedef signed __int64 LONG64;
cpp_quote("#endif")
typedef unsigned __int64 QWORD;
cpp_quote("#ifndef _WINNT_")
typedef short SHORT;
cpp_quote("#endif")
typedef __int64 TIME;
cpp_quote("#ifndef _WINNT_")
typedef char CHAR, *PCHAR;
typedef unsigned char UCHAR, *PUCHAR;
cpp_quote("#endif")
cpp_quote("#ifndef _WINDEF_H")
typedef unsigned int UINT;
cpp_quote("#endif")
cpp_quote("#ifndef _BASETSD_H_")
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
typedef unsigned __int64 UINT64;
cpp_quote("#endif")
cpp_quote("#ifndef _WINNT_")
typedef unsigned long ULONG, *PULONG;
cpp_quote("#endif")
cpp_quote("#ifndef _BASETSD_H_")
typedef unsigned int ULONG32;
typedef unsigned __int64 ULONG64;
cpp_quote("#endif")
cpp_quote("#ifndef _WINNT_")
typedef unsigned __int64 ULONGLONG;
typedef unsigned short USHORT;
cpp_quote("#endif")
cpp_quote("#ifndef _WINDEF_H")
typedef unsigned short WORD, *PWORD, *LPWORD;
cpp_quote("#endif")
cpp_quote("#ifndef _WINNT_")
typedef long LONG, *PLONG;
cpp_quote("#endif")
cpp_quote("#ifndef _WINDEF_H")
typedef long *LPLONG;
cpp_quote("#endif")
cpp_quote("#ifndef _WINNT_")
typedef signed __int64 LONGLONG;
cpp_quote("#endif")

cpp_quote("#ifndef _WINDEF_H")
typedef float FLOAT;
cpp_quote("#endif")
cpp_quote("#ifndef __wtypes_h__")
typedef double DOUBLE;
cpp_quote("#endif")

cpp_quote("#ifndef _WINNT_")
typedef BYTE BOOLEAN, *PBOOLEAN;
cpp_quote("#endif")
cpp_quote("#ifndef _BASETSD_H_")
#ifdef _WIN64
typedef __int64 LONG_PTR;
typedef unsigned __int64 ULONG_PTR;
#else
typedef LONG LONG_PTR;
typedef ULONG ULONG_PTR;
#endif
typedef ULONG_PTR SIZE_T;
typedef ULONG_PTR DWORD_PTR;
cpp_quote("#endif")
typedef DWORD NET_API_STATUS;
cpp_quote("#ifndef _WINNT_")
typedef ULONGLONG DWORDLONG, *PDWORDLONG;
cpp_quote("#endif")
typedef DWORD HCALL;
//typedef DWORD HRESULT;

cpp_quote("#ifndef _WINNT_")
typedef void *HANDLE;
typedef void /*VOID,*/ *PVOID;
cpp_quote("#endif")
cpp_quote("#ifndef __WINE_RPCDCE_H")
typedef void *RPC_BINDING_HANDLE;
cpp_quote("#endif")
typedef [context_handle] void *PCONTEXT_HANDLE;
typedef PCONTEXT_HANDLE *PPCONTEXT_HANDLE;

cpp_quote("#ifndef _WINNT_")
typedef wchar_t WCHAR, *PWCHAR;
cpp_quote("#if 0")
typedef wchar_t UNICODE;
cpp_quote("#endif")
typedef const char *LPCSTR;
typedef const wchar_t *LPCWSTR;
typedef char *PSTR, *LPSTR;
typedef wchar_t *LPWSTR, *PWSTR;
cpp_quote("#endif")
typedef const wchar_t *LMCSTR;
typedef WCHAR *LMSTR;
cpp_quote("#ifndef __wtypes_h__")
typedef WCHAR *BSTR;
cpp_quote("#endif")

cpp_quote("#if 0")
#ifdef Unicode
typedef LPCWSTR LPCTSTR;
typedef LPWSTR LPTSTR;
typedef WCHAR TCHAR;
#else
typedef LPCSTR LPCTSTR;
typedef LPSTR LPTSTR;
typedef CHAR TCHAR;
#endif
cpp_quote("#endif")

/* Common data structures */

cpp_quote("#if 0")

typedef struct _FILETIME {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

typedef struct _GUID {
    DWORD Data1;
    WORD Data2;
    WORD Data3;
    BYTE Data4[8];
} GUID, UUID, *PGUID;

typedef struct _LARGE_INTEGER {
    LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;

typedef DWORD LCID;

cpp_quote("#endif")

typedef struct _RPC_UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    [size_is(MaximumLength/2), length_is(Length/2)] LPWSTR Buffer;
} RPC_UNICODE_STRING, *PRPC_UNICODE_STRING;

cpp_quote("#if 0")

typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;

typedef struct _UINT128 {
    UINT64 lower;
    UINT64 upper;
} UINT128, *PUINT128;

typedef struct _ULARGE_INTEGER {
    ULONGLONG QuadPart;
} ULARGE_INTEGER, *PULARGE_INTEGER;

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    [size_is(MaximumLength/2), length_is(Length/2)] LPWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

cpp_quote("#endif")

/* Constructed security types */

cpp_quote("#if 0")

typedef struct _SID_IDENTIFIER_AUTHORITY {
    BYTE Value[6];
} SID_IDENTIFIER_AUTHORITY;

typedef struct _SID {
    BYTE Revision;
    BYTE SubAuthorityCount;
    SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
    [size_is(SubAuthorityCount)] DWORD SubAuthority[*];
} SID, *PSID;

typedef struct _ACCESS_MASK {
    DWORD ACCESS_MASK;
} ACCESS_MASK, *PACCESS_MASK;

typedef struct _ACE_HEADER {
    UCHAR AceType;
    UCHAR AceFlags;
    USHORT AceSize;
} ACE_HEADER, *PACE_HEADER;

typedef struct _ACCESS_ALLOWED_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} ACCESS_ALLOWED_ACE, *PACCESS_ALLOWED_ACE;

typedef struct _ACCESS_ALLOWED_OBJECT_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD Flags;
    GUID ObjectType;
    GUID InheritedObjectType;
    DWORD SidStart;
} ACCESS_ALLOWED_OBJECT_ACE, *PACCESS_ALLOWED_OBJECT_ACE;

typedef struct _ACCESS_DENIED_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} ACCESS_DENIED_ACE, *PACCESS_DENIED_ACE;

typedef struct _ACCESS_ALLOWED_CALLBACK_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} ACCESS_ALLOWED_CALLBACK_ACE, *PACCESS_ALLOWED_CALLBACK_ACE;

typedef struct _ACCESS_DENIED_CALLBACK_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} ACCESS_DENIED_CALLBACK_ACE, *PACCESS_DENIED_CALLBACK_ACE;

typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD Flags;
    GUID ObjectType;
    GUID InheritedObjectType;
    DWORD SidStart;
} ACCESS_ALLOWED_CALLBACK_OBJECT_ACE, *PACCESS_ALLOWED_CALLBACK_OBJECT_ACE;

typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD Flags;
    GUID ObjectType;
    GUID InheritedObjectType;
    DWORD SidStart;
} ACCESS_DENIED_CALLBACK_OBJECT_ACE, *PACCESS_DENIED_CALLBACK_OBJECT_ACE;

typedef struct _SYSTEM_AUDIT_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} SYSTEM_AUDIT_ACE, *PSYSTEM_AUDIT_ACE;

typedef struct _SYSTEM_AUDIT_CALLBACK_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} SYSTEM_AUDIT_CALLBACK_ACE, *PSYSTEM_AUDIT_CALLBACK_ACE;

typedef struct _SYSTEM_MANDATORY_LABEL_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD SidStart;
} SYSTEM_MANDATORY_LABEL_ACE, *PSYSTEM_MANDATORY_LABEL_ACE;

typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE {
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    DWORD Flags;
    GUID ObjectType;
    GUID InheritedObjectType;
    DWORD SidStart;
} SYSTEM_AUDIT_CALLBACK_OBJECT_ACE, *PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE;

typedef struct _ACL {
    UCHAR AclRevision;
    UCHAR Sbz1;
    USHORT AclSize;
    USHORT AceCount;
    USHORT Sbz2;
} ACL, *PACL;

typedef struct _SECURITY_DESCRIPTOR {
    UCHAR Revision;
    UCHAR Sbz1;
    USHORT Control;
    ULONG Owner;
    ULONG Group;
    ULONG Sacl;
    ULONG Dacl;
} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR;

typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION;

cpp_quote("#endif")

typedef struct _RPC_SID {
    UCHAR Revision;
    UCHAR SubAuthorityCount;
    SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
    [size_is(SubAuthorityCount)] DWORD SubAuthority[];
} RPC_SID, *PRPC_SID;

cpp_quote("#endif /* _DTYP_IDL */")

然后结合ms-dtyp.idl里面的类型,制作需要生成通讯接口的IDL文件,比如我现在就做个简单的RPC请求数据接口文件PostTest.idl:

#include "ms-dtyp.idl"

[
  uuid(D0FECC64-60E2-4d88-A0FD-39210BB009CA),
  version(2.0)
]


interface PostTest
{
DWORD RpcGetResult( 
    [unique][string][in] LPWSTR lpParam,
    [out, string, size_is(*lpcchResult + 1)] LPWSTR lpResult,
    [out][in] DWORD *lpcchResult);

BOOL RpcSafeExit();
}

到这里,我们的RPC的IDL接口文件制作完成,如需丰富IDL文件里的通讯接口,只需多加几个类似的RpcGetResult函数即可

        下一步,我们开始编译IDL文件生成对应的.h,.c文件,分别用于客户端服务端项目中,Window RPC的编译方法有两种,一种是用MIDL.exe,自己用everything搜素,可以搜素到本地的MIDL.exe路径,把两个IDL文件复制到MIDL.exe同目录,然后运行MIDL.exe  PostTest.idl命令即可生成PostTest_h.h,PostTest_c.c,PostTest_s.c三个文件,这三个文件就能直接用到项目中了,第二种编译方法也非常简单,我一般都是用第二种方法,就是新建一个随便命名的空项目,然后将两个IDL文件加入到项目,编译项目即可在项目目录生成PostTest_h.h,PostTest_c.c,PostTest_s.c三个文件

           最后就是将这三个文件用到项目中了,我直接上代码,至于为啥我代码这么用这么写,你们可以自己再多查资料,我这边只简单介绍下用法

复制PostTest_h.h,PostTest_s.c文件到服务器项目目录中,添加文件到项目中,编写服务端调用main函数

WinRPCServer.cpp

// WinRPCServer.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <Windows.h>
#include <string>
#include <rpc.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Rpcrt4.lib")
#include "PostTest_h.h"
using namespace std;



void * __RPC_USER MIDL_user_allocate(size_t len)
{
	return (malloc(len));
}

void __RPC_USER MIDL_user_free(void* ptr)
{
	free(ptr);
}

DWORD RpcGetResult(handle_t IDL_handle,LPWSTR lpParam,LPWSTR lpResult,DWORD *lpcchResult)
{
	wstring strType = lpParam;
	wchar_t *szResult = new wchar_t[100];
	wmemset(szResult,0,100);
	if (strType == L"01")
	{
		wcscpy(szResult,L"1111111\r\n");
	}
	else
	{
		wcscpy(szResult,L"2222222\r\n");
	}

	if (*lpcchResult <= wcslen(szResult))
	{
		wcsncpy_s(lpResult,*lpcchResult,szResult,*lpcchResult - 1);
		lpResult[*lpcchResult - 1] = '\0';
		*lpcchResult--;
	}
	else
	{
		wcscpy_s(lpResult,*lpcchResult,szResult);
		*lpcchResult = wcslen(lpResult);
	}
	return 1;
}


BOOL RpcSafeExit(handle_t IDL_handle)
{
	//ExitProcess( 0 );
	return TRUE;
}
BOOL StartRPC() 
{
	/*	wchar_t *pArgv = (wchar_t*)param;*/
	RPC_STATUS status = 0;
	unsigned int nMinCalls = 1;
	unsigned int nMaxCalls = 20;
	// 	int iNum = 0;
	// 	iNum =  _wtoi(pArgv);
	char szAppName[256] = {0};
	sprintf_s(szAppName,256,"WANG_XIAOMING_RPC_GLOBAL_VER_001");

	status = RpcServerUseProtseqEpA((unsigned char *)"ncalrpc", RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
		(unsigned char *)szAppName, NULL );
	if ( status != 0 )
	{
		return FALSE;
	}
	OutputDebugStringA("服务端启动成功");

	status = RpcServerRegisterIfEx(
		PostTest_v2_0_s_ifspec,
		NULL,
		NULL,
		RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
		0,
		NULL);
	if ( status != 0 )
	{
		return FALSE;
	}

	status = RpcServerListen(
		nMinCalls,
		nMaxCalls,
		TRUE );
	return TRUE;
}


int main(int argc, char* argv[])
{
	if (StartRPC())
	{
		while (1)
		{
			Sleep(1000);
		}
	}
	printf("Close");
	getchar();
	return 0;
}

复制PostTest_h.h,PostTest_c.c文件到客户端请求项目目录中,添加文件到项目中,编写客户端调用main函数

WinRPCClient.cpp

// WinRPCClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>
#include <rpc.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Rpcrt4.lib")
#include "PostTest_h.h"

RPC_BINDING_HANDLE		g_RpcLink;		//RPC连接


void * __RPC_USER MIDL_user_allocate(size_t len)
{
	return (malloc(len));
}

void __RPC_USER MIDL_user_free(void* ptr)
{
	free(ptr);
}



bool InitRpc()
{
	bool bRet = true;
	RPC_STATUS status;
	unsigned char * pszStringBinding = NULL;
	int iSpc = 1;
	char szSpc[50] = {0};
	sprintf_s(szSpc,"WANG_XIAOMING_RPC_GLOBAL_VER_001");
	status = RpcStringBindingComposeA(
		NULL,
		(unsigned char *)"ncalrpc", //本地的RPC
		NULL,
		(unsigned char *)szSpc,
		NULL,
		&pszStringBinding );
	if ( status != 0 )
	{
		return false;
	}
	status = RpcBindingFromStringBindingA(pszStringBinding, &g_RpcLink );
	if ( status != 0 )
	{
		return false;
	}
	printf("Server RpcInit Suc\r\n");
	return true;
}


bool CheckRpcConnect()
{
	if (g_RpcLink == NULL)
	{
		if (!InitRpc())
		{
			return false;
		}
	}

	RpcTryExcept
	{
		RPC_STATUS status;
		status = RpcMgmtIsServerListening( g_RpcLink );
		if (status == RPC_S_OK)
		{
			printf("ServerListening Suc\r\n");
			return true;
		}
	}
	RpcExcept(1)
	{
		return false;
	}
	RpcEndExcept
		return false;
}


//初始化RPC连接链
bool SendRpcRequest(wchar_t *pParam,wchar_t *pResult,DWORD &iLen)
{
	RpcTryExcept
	{
		if (RpcGetResult(g_RpcLink,pParam,pResult,&iLen) != 0 )
		{
			return true;
		}
		return true;;
	}
	RpcExcept(1)
	{
		ULONG ulCode = RpcExceptionCode();
		return false;
	}
	RpcEndExcept
	return true;
}

int _tmain(int argc, _TCHAR* argv[])
{

	if (CheckRpcConnect())
	{
		wchar_t* pResult = new wchar_t[1024];
		wmemset(pResult,0,1024);
		DWORD dwLen = 1024;
		
		SendRpcRequest((LPWSTR)L"01",pResult,dwLen);
		wprintf(pResult);
	}
	
	printf("Close");
	getchar();
	return 0;
}

然后先运行server程序,后运行client,就可以查看到请求的数据了,我这边的例子用的是本地RPC调用,如需运用网络RPC调用,可自行查询相关例子,修改对应参数

猜你喜欢

转载自blog.csdn.net/u010340160/article/details/84561893
RPC