xmlrpc学习笔记(c++示例代码)

xmlrpc是一种通过网络进行过程调用的快速并且简单的方法。xmlrpc将过程调用需要的参数转换成xml文档,并以http协议发送给远端服务器,服务器将以xml协议将结果回复给客户端。以下是在使用xmlrpc时需要用到的参考资料。

xmlrpc网站: http://xmlrpc-c.sourceforge.net/
xmlrpc源代码下载: https://sourceforge.net/p/xmlrpc-c/code/HEAD/tree/

XML-RPC用户手册: http://xmlrpc-c.sourceforge.net/doc/#examples
介绍了什么是xmlrpc, 介绍了C/C++应用程序使用xmlrpc时需要用到的lib文件以及每个lib文件大概的作用,手册里面还有C和C++实现的xmlrpc客户端和服务器示例代码。

General Library Information - C: http://xmlrpc-c.sourceforge.net/doc/libgeneral.html
介绍了xmlrpc-c的C编程库

general library information - C++: http://xmlrpc-c.sourceforge.net/doc/libgeneral++.html
介绍了xmlrpc-c的C++编程库

libxmlrpc: http://xmlrpc-c.sourceforge.net/doc/libxmlrpc.html
详细讲解了libxmlrpc库
libxmlrpc++: http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html
详细讲解了libxmlrpc++库

--------------------------------------------------------------------------------------------------------------------

以下过程基于windows平台

一. 下载xmlrpc-c源码

下载地址如上。在下载的工程文件中找到目录Windows,进入目录并查看ReadMeWin32.txt文件,提示要你运行ConfigureWin32.bat批处理文件(这个批处理文件就是用来生成一些.h头文件,这些头文件提供了一些宏定义,在windows平台中编译生成xmlrpc相关库的时候需要使用),双击运行就好。用vs打开工程(Windows->project),可以发现所有的xmlrpc库都是动态库,编译并生成相关的库。在编译过程中可能会出现一些错误,基本上都是小错误,很容易定位并解决。

二. 编写测试代码

在测试代码中,链接到项目中的lib文件只需要两个(libxmlrpc++.lib libxmlrpc_util++.lib)。

可能需要的基础知识:

2.1 在xmlrpc中,所有的接口使用的是特殊数据类型,如value_int,、value_i8等。所有的这些

数据类型都继承自一个名叫value的类,value可以表示任何派生类对象(你可以将任何派生类

对象赋值给value对象)。xmlrpc数据类型与C/C++数据类型之间的转换只需要调用一个名为

cvalue的成员函数,使用时需要注意value并不是一个抽象类型,value中的cvalue不是虚函数,

每个派生类各自实现了cvalue函数。当你得到一个value对象的时候,你就需要判断他是什么数据类型,

这时候需要使用value的另外一个成员函数type。type只存在与value类中,使用type能够得到该value具体

表示的对象的类型是什么,它返回的是type_t对象。type_t对象是枚举类型,定义了所有数据类型。

2.2 xmlrpc内部使用智能指针管理对象,为实现智能管理,xmlrpc中的类都继承自girmem::autoObject

对于从girmem::autoObject派生的每个类,都有一个派生自autoObjectPtr的类,名字相差一个后缀Ptr。

在xmlrpc中想要使用autoObject对象时,使用的是对应的autoObjectPtr对象,因为autoObject构造函数是

私有的,内部使用std::auto_ptr,它声明了autoObjectPtr类为友元类。

2.3 所有接口调用中如果出现错误就会跑出一个xmlrpc特有的girerr::error对象,error继承自std::exception。

2.4 使用xmlrpc可以很方便的进行Base64编码和解码,只需要使用两个接口base64FromBytesbytesFromBase64

2.5 xmlrpc客户端可以同步请求服务器,也可以异步请求服务器,但貌似异步请求没有在libxmlrpc++库中实现,要想使用异步请求,只能写C代码了。

以下示例代码是从上面贴出的文档中找到的,做了些许修改,仅为测试而用。

我定义了两个宏XMLRPC_CPP、XMLRPC_C,目的是方便编译C++或者C的代码。

目前只做了对C++的测试,所以只编译了C++部分代码,亲测可用,

至于C的用到再说吧。

客户端代码:

#include "stdafx.h"
#include 
#include 
#define XMLRPC_CPP 1
#define XMLRPC_C 0

#if XMLRPC_CPP

#include 
#include 

#elif XMLRPC_C



#endif

using namespace std;
using namespace xmlrpc_c;

int _tmain(int argc, _TCHAR* argv[])
{
#if XMLRPC_CPP
	string const serverUrl("http://10.10.30.166:8088/RPC2");
	string const methodName("sample.add");
	//string const methodName("SuspectPersonManage");
	xmlrpc_c::clientSimple myClient;
	xmlrpc_c::value result;
	xmlrpc_c::paramList paramLst;
	xmlrpc_c::cstruct paramIn;
	paramIn["first"] = xmlrpc_c::value_int(1);
	paramIn["second"] = xmlrpc_c::value_int(2);
	paramLst.addc(paramIn);
	//myClient.call(serverUrl, methodName, "ii", &result, 5, 7);
	myClient.call(serverUrl, methodName, paramLst, &result);

	int const sum((xmlrpc_c::value_int(result)));
	// Assume the method returned an integer; throws error if not

	cout << "Result of RPC (sum of 5 and 7): " << sum << endl;

	//string strXmlRpcSrvUrl("http://10.10.30.166:9090/RPC2");
	//xmlrpc_c::clientSimple myClient;
	//xmlrpc_c::value result;
	//xmlrpc_c::paramList paramLst;
	//xmlrpc_c::cstruct struct_param;
	//xmlrpc_c::carray image_array_param;
	//xmlrpc_c::carray imagetype_array_param;

	//struct_param["CommandType"] = value_int(0);
	//struct_param["Name"] = value_string("luffy");
	//struct_param["Sex"] = value_int(1);
	//struct_param["IdNumber"] = value_string("123456789");
	//struct_param["Phone"] = value_string("");
	//struct_param["Address"] = value_string("");
	//struct_param["person_type"] = value_string("1");
	//image_array_param.push_back(value_string("abcdefg"));
	//imagetype_array_param.push_back(value_int(0));
	//struct_param["Image"] = value_array(image_array_param);
	//struct_param["ImageType"] = value_array(imagetype_array_param);

	//paramLst.addc(struct_param);

	//myClient.call(strXmlRpcSrvUrl, "SuspectPersonManage", paramLst, &result);

#elif XMLRPC_C
	xmlrpc_env env;
	xmlrpc_value * resultP;
	int sum;
	char * const clientName = "XML-RPC C Test Client";
	char * const clientVersion = "1.0";
	char * const url = "http://localhost:8080/RPC2";
	char * const methodName = "sample.add";

	/* Initialize our error-handling environment. */
	xmlrpc_env_init(&env);

	/* Start up our XML-RPC client library. */
	xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, clientName, clientVersion, NULL, 0);
	[handle possible failure of above]

	/* Make the remote procedure call */
	resultP = xmlrpc_client_call(&env, url, methodName,
		"(ii)", (xmlrpc_int32)5, (xmlrpc_int32)7);
	[handle possible failure of above]

	/* Print out the sum the server returned */
	xmlrpc_parse_value(&env, resultP, "i", &sum);
	[handle possible failure of above]

	printf("The sum  is %d\n", sum);

	/* Dispose of our result value. */
	xmlrpc_DECREF(resultP);

	/* Clean up our error-handling environment. */
	xmlrpc_env_clean(&env);

	/* Shutdown our XML-RPC client library. */
	xmlrpc_client_cleanup();
#endif

	return 0;
}

服务端代码:

#include "stdafx.h"
#include 
#define XMLRPC_CPP 1
#define XMLRPC_C 0

#if XMLRPC_CPP

#include 
#include 
#include 

#elif XMLRPC_C

#include 
#include 
#include 

#endif


#if XMLRPC_CPP

class sampleAddMethod : public xmlrpc_c::method {
public:
	sampleAddMethod() {}

	void
		execute(xmlrpc_c::paramList const& paramList,
		xmlrpc_c::value *   const  retvalP) {
//			xmlrpc_c::cstruct tmp  = paramList.getStruct(0);

// 			int const addend(paramList.getInt(0));
// 			int const adder(paramList.getInt(1));
//			paramList.verifyEnd(2);

			xmlrpc_c::cstruct struct_param = paramList.getStruct(0);
			assert(struct_param["first"].type() == xmlrpc_c::value::TYPE_INT);
			assert(struct_param["second"].type() == xmlrpc_c::value::TYPE_INT);
			xmlrpc_c::value_int value1 = struct_param["first"];
			xmlrpc_c::value_int value2 = struct_param["second"];

			int const addend =  value1.cvalue();
			int const adder = value2.cvalue();

			paramList.verifyEnd(1);	//检测参数个数,如果位置1不是结尾标志(类似eof),那么抛出异常。

			*retvalP = xmlrpc_c::value_int(addend + adder);
	}
};

#elif XMLRPC_C

static xmlrpc_value * sample_add(xmlrpc_env*   const envP,
								 xmlrpc_value* const paramArrayP,
								 void* const serverContext)
{

	xmlrpc_int32 x, y, z;

	/* Parse our argument array. */
	xmlrpc_parse_value(envP, paramArrayP, "(ii)", &x, &y);
	if (envP->fault_occurred)
		return NULL;

	/* Add our two numbers. */
	z = x + y;

	/* Return our result. */
	return xmlrpc_build_value(envP, "i", z);
}

#endif


int _tmain(int argc, _TCHAR* argv[])
{
#if XMLRPC_CPP
	xmlrpc_c::registry myRegistry;

	xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod);

	myRegistry.addMethod("sample.add", sampleAddMethodP);

	xmlrpc_c::serverAbyss myAbyssServer(
		myRegistry,
		8088,              // TCP port on which to listen
		"/tmp/xmlrpc_log"  // Log file
		);

	myAbyssServer.run();
	// xmlrpc_c::serverAbyss.run() never returns
	assert(false);
#elif XMLRPC_C
	xmlrpc_server_abyss_parms serverparm;
	xmlrpc_registry * registryP;
	xmlrpc_env env;

	xmlrpc_env_init(&env);

	registryP = xmlrpc_registry_new(&env);

	xmlrpc_registry_add_method(
		&env, registryP, NULL, "sample.add", &sample_add, NULL);

	serverparm.config_file_name = argv[1];
	serverparm.registryP = registryP;

	printf("Starting XML-RPC server...\n");

	xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(registryP));

#endif

	return 0;
}

运行结果:



服务器会报出这种错误,因为这个日志文件确实没有,我也没深究,不影响使用就行。

你可能感兴趣的:(第三方库学习笔记)