xmlrpc远程函数式服务调用,C++作为服务端,python、C++客户端远程函数调用

2 篇文章 0 订阅
1 篇文章 0 订阅

xmlrpc远程函数式服务调用,C++作为服务端,python、C++客户端通过http进行调用

C++编写服务端

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

// xmlrcp.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

#include <assert.h>
#include <xmlrpc-c/base.hpp>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>

#include <codecvt>
#include <xmlrpc-c/base64.hpp>
#include <xmlrpc-c/base64.hpp>

class sampleAddMethod : public xmlrpc_c::method {
public:
	sampleAddMethod() {}
	void execute(xmlrpc_c::paramList const& paramList,
		xmlrpc_c::value* const retvalP = NULL) {


		int a = paramList.getInt(0);
		int b = paramList.getInt(1);
		*retvalP = xmlrpc_c::value_int(a + b);
		/*std::cout << "struct success**" << std::endl;
		assert(struct_param["first"].type() == xmlrpc_c::value::TYPE_INT);
		assert(struct_param["first"].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);
		*retvalP = xmlrpc_c::value_int(addend + adder);*/


	}

};
class sampleAddMethod1 : public xmlrpc_c::method {
public:
    sampleAddMethod1() {}

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

//测试乱码
class GetEncoding : public xmlrpc_c::method {
public:
    GetEncoding() {}
    void execute(xmlrpc_c::paramList const& paramList,
        xmlrpc_c::value* const retvalP = NULL) {
        std::vector<xmlrpc_c::value> result;
        std::string inputstr = paramList.getString(0);
        printf("输入字符串:%s \n", UTF8ToGBK(inputstr).c_str());
        std::cout << "输入字符串" << UTF8ToGBK(inputstr) << std::endl;
        std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
        std::string utf8_str = converter.to_bytes(L"该符号在函数_wmain 中被引用");
        //std::string c = base64Encode(utf8_str);
        //std::string str = "该符号在函数_wmain 中被引用";
        //std::vector<unsigned char> ss = xmlrpc_c::bytesFromBase64(str);
        result.push_back(xmlrpc_c::value_string("hello"));
        result.push_back(xmlrpc_c::value_string("world"));
        //result.push_back(xmlrpc_c::value_bytestring(ss));
        //std::vector<unsigned char> ss1 = xmlrpc_c::bytesFromBase64("English");
        //result.push_back(xmlrpc_c::value_bytestring(ss1));
        std::wstring_convert<std::codecvt_utf8<wchar_t>> converter1;
        std::string utf8_str1 = converter1.to_bytes(L"中文汉字乱码");
        result.push_back(xmlrpc_c::value_string(converter1.to_bytes(L"中文汉字乱码")));
        //result.push_back(xmlrpc_c::value_string(converter.to_bytes(("English"))));
        //result.push_back(xmlrpc_c::value_string(converter.from_bytes("中文汉字乱码")));
        result.push_back(xmlrpc_c::value_string(StringCoding("中文汉字乱码 hahah")));
        result.push_back(xmlrpc_c::value_string(StringCoding("中文汉字乱码")));
        result.push_back(xmlrpc_c::value_string(StringCoding("中文汉字乱码 ")));
        result.push_back(xmlrpc_c::value_string(StringCoding("Hello world 123")));
        result.push_back(xmlrpc_c::value_string(StringCoding("123456789")));
        result.push_back(xmlrpc_c::value_string(UnicodeToUTF8(StringToUnicode("中文汉字乱码"))));
        result.push_back(xmlrpc_c::value_string(UnicodeToUTF8(StringToUnicode("Hello world"))));
        //result.push_back(xmlrpc_c::value_string("中文汉字乱码"));
        result.push_back(xmlrpc_c::value_string(UnicodeToUTF8((L"中文汉字乱码"))));
        // byte[] byteData = Encoding.UTF8.GetBytes("你好中国");
         //*retvalP = xmlrpc_c::value_string("http server connected");
        *retvalP = xmlrpc_c::value_array(result);
    }
    std::string StringCoding(const std::string& str)
    {
        std::string result;
        //获取缓冲区大小,并申请空间,缓冲区大小按字符计算  
        int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
        TCHAR* buffer = new TCHAR[len + 1];
        //多字节编码转换成宽字节编码  
        MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
        buffer[len] = '\0'; //添加字符串结尾 
        try {
            std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
            result = wcv.to_bytes(buffer);
        }
        catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
        //删除缓冲区并返回值
        delete[] buffer;
        return result;
    }
    std::string UTF8ToGBK(const std::string& str)
    {
        std::string result;
        //获得临时变量的大小
        int i = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
        WCHAR* strSrc = new WCHAR[i + 1];
        MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, strSrc, i);
        //获得临时变量的大小
        i = WideCharToMultiByte(CP_ACP, 0, strSrc, -1, NULL, 0, NULL, NULL);
        LPSTR szRes = new CHAR[i + 1];
        WideCharToMultiByte(CP_ACP, 0, strSrc, -1, szRes, i, NULL, NULL);
        result = szRes;
        delete[]strSrc;
        delete[]szRes;
        return result;
    }
    std::wstring StringToUnicode(const std::string& str)
    {
        std::wstring result;
        //获取缓冲区大小,并申请空间,缓冲区大小按字符计算  
        int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
        TCHAR* buffer = new TCHAR[len + 1];
        //多字节编码转换成宽字节编码  
        MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
        buffer[len] = '\0';             //添加字符串结尾  
        //删除缓冲区并返回值  
        result.append(buffer);
        delete[] buffer;
        return result;
        /*WCHAR sectionName[100];
        memset(sectionName, 0, sizeof(sectionName));
        MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length() + 1, sectionName, sizeof(sectionName) / sizeof(sectionName[0]));
        return sectionName;*/
    }

    std::string UnicodeToUTF8(const std::wstring& wstr)
    {
        std::string ret;
        try {
            std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
            ret = wcv.to_bytes(wstr);
        }
        catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
        return ret;
    }
    std::wstring UTF8ToUnicode(const std::string& str)
    {
        std::wstring ret;
        try {
            std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
            ret = wcv.from_bytes(str);
        }
        catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
        return ret;
    }
    std::wstring ANSIToUnicode(const std::string& str)
    {
        std::wstring ret;
        std::mbstate_t state = {};
        const char* src = str.data();
        size_t len = std::mbsrtowcs(nullptr, &src, 0, &state);
        if (static_cast<size_t>(-1) != len) {
            std::unique_ptr< wchar_t[] > buff(new wchar_t[len + 1]);
            len = std::mbsrtowcs(buff.get(), &src, len, &state);
            if (static_cast<size_t>(-1) != len) {
                ret.assign(buff.get(), len);
            }
        }
        return ret;
    }
};
//测试连通性
class GetConnect : public xmlrpc_c::method {
public:
    GetConnect() {}
    void execute(xmlrpc_c::paramList const& paramList,
        xmlrpc_c::value* const retvalP = NULL) {
        printf("http服务连接成功\n");
        std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
        std::string utf8_str = converter.to_bytes(L"http 服务连接成功");
        *retvalP = xmlrpc_c::value_string(utf8_str);
    }
};

//发送数组
class SendArray : public xmlrpc_c::method {
public:
    SendArray() {}
	void execute(xmlrpc_c::paramList const& paramList,
		xmlrpc_c::value* const retvalP = NULL) {

		xmlrpc_c::carray array1 = paramList.getArray(0);
		xmlrpc_c::carray array2 = paramList.getArray(1);
		
		int length = array1.size();
		std::vector<xmlrpc_c::value> result;
		for (int i = 0; i < length; i++)
		{
			int no1 = xmlrpc_c::value_int(array1[i]);
			int no2 = xmlrpc_c::value_int(array2[i]);
			printf("数据1:%d,数据2:%d\n", no1, no2);
			std::vector<xmlrpc_c::value> entrust_value;
			entrust_value.push_back(array1[i]);
			entrust_value.push_back(array2[i]);
			xmlrpc_c::value arrayArray1 = xmlrpc_c::toValue(entrust_value);
			result.push_back(arrayArray1);
		}
		*retvalP = xmlrpc_c::value_array(result);
	}
};
int main()
{
	//std::cout << "Hello World!\n";
	xmlrpc_c::registry myRegistry;
	xmlrpc_c::methodPtr const sampleAddMethodP = new sampleAddMethod();
	myRegistry.addMethod("add", sampleAddMethodP);
    xmlrpc_c::methodPtr const sampleAddMethodP1 = new sampleAddMethod1();
    myRegistry.addMethod("add1", sampleAddMethodP1);
	xmlrpc_c::methodPtr const send_array = new SendArray();
	myRegistry.addMethod("send_array", send_array);
    xmlrpc_c::methodPtr const coding = new GetEncoding();
    myRegistry.addMethod("coding", coding);
    //测试连通性
    xmlrpc_c::methodPtr const get_connnect = new GetConnect();
    myRegistry.addMethod("get_connnect", get_connnect);
    // 端口号、日志文件、保持连接时间(应该是秒?)、最大连接数
	xmlrpc_c::serverAbyss myAbyssServer(myRegistry, 8088,"",6000,100//,"xmlrpc_log"             // TCP port on which to listen		
		//"/tmp/xmlrpc_log"  // Log file		
	);
    //开启服务
	myAbyssServer.run();	// xmlrpc_c::serverAbyss.run() never returns	
	assert(false);
	return 0;
}

继承xmlrpc_c::method类的基类实现了一个调用的 execute方法,代码中共有5个类继承了xmlrpc_c::method的基类,也就是有5个http的接口,分别是接收参数、返回数据、乱码处理、测试连通性、计算加法等的demo,main方法中
注册了这五个接口到http的服务中

	xmlrpc_c::registry myRegistry;
	xmlrpc_c::methodPtr const sampleAddMethodP = new sampleAddMethod();
	myRegistry.addMethod("add", sampleAddMethodP);
    xmlrpc_c::methodPtr const sampleAddMethodP1 = new sampleAddMethod1();
    myRegistry.addMethod("add1", sampleAddMethodP1);
	xmlrpc_c::methodPtr const send_array = new SendArray();
	myRegistry.addMethod("send_array", send_array);
    xmlrpc_c::methodPtr const coding = new GetEncoding();
    myRegistry.addMethod("coding", coding);
    //测试连通性
    xmlrpc_c::methodPtr const get_connnect = new GetConnect();
    myRegistry.addMethod("get_connnect", get_connnect);

然后设置端口号、日志文件、保持连接时间(应该是秒?)、最大连接数

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

最后开启http服务:

//开启服务
	myAbyssServer.run();	// xmlrpc_c::serverAbyss.run() never returns

C++编写客户端

C++客户端代码如下

#include <iostream>
#include <xmlrpc-c/base.hpp>
#include <xmlrpc-c/client_simple.hpp>
#include <codecvt>
#include <xmlrpc-c/server_abyss.hpp>


using namespace std;
using namespace xmlrpc_c;


string UTF8ToGBK(const string& str)
{
	string result;
	//获得临时变量的大小
	int i = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
	WCHAR* strSrc = new WCHAR[i + 1];
	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, strSrc, i);
	//获得临时变量的大小
	i = WideCharToMultiByte(CP_ACP, 0, strSrc, -1, NULL, 0, NULL, NULL);
	LPSTR szRes = new CHAR[i + 1];
	WideCharToMultiByte(CP_ACP, 0, strSrc, -1, szRes, i, NULL, NULL);
	result = szRes;
	delete[]strSrc;
	delete[]szRes;
	return result;
}
wchar_t* StringToDword(const string& str)
{
	wstring result;
	//获取缓冲区大小,并申请空间,缓冲区大小按字符计算  
	int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
	TCHAR* buffer = new TCHAR[len + 1];
	//多字节编码转换成宽字节编码  
	MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
	buffer[len] = '\0';             //添加字符串结尾  
	//删除缓冲区并返回值  
	result.append(buffer);
	delete[] buffer;
	wchar_t* inputStr = new wchar_t;
	wcscpy(inputStr, result.c_str());
	return inputStr;
}

int main()
{
	string const serverUrl("http://localhost:8088/RPC2");
	//string const methodName= "add";
	//string const methodName("SuspectPersonManage");
	xmlrpc_c::clientSimple myClient;
	xmlrpc_c::value result;
	myClient.call(serverUrl, "get_connnect", &result);
	string ret_string = xmlrpc_c::value_string(result);
	string ss = UTF8ToGBK(ret_string);
	cout << ss << endl;
	printf("返回信息:%s\n", UTF8ToGBK(ret_string).c_str());


	xmlrpc_c::value coding_result;
	//调用coding方法,w为宽字符串参数,
	myClient.call(serverUrl, "coding","w", &coding_result, StringToDword("中文乱码"));
	//返回值进行处理
	std::vector<xmlrpc_c::value> vector_result;
	xmlrpc_c::fromValue(vector_result, coding_result);
	for (int i = 0; i < vector_result.size(); i++)
	{
		string out = xmlrpc_c::value_string(vector_result[i]);
		cout <<"输出参数:"<< UTF8ToGBK(out) << endl;
	}

	
	xmlrpc_c::value add_result;
	myClient.call(serverUrl, "add", "ii", &add_result, 5, 7);
	int const sum((xmlrpc_c::value_int(add_result)));
	// Assume the method returned an integer; throws error if not

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

	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, paramLst, &result);
	xmlrpc_c::value add1_result;
	myClient.call(serverUrl, "add1", paramLst, &add1_result);
	cout << "Result of RPC (sum of 1 and 2): " << xmlrpc_c::value_int(add1_result) << endl;
	//发送集合参数
	std::vector<int> input1;
	std::vector<int> input2;
	for (int i = 0; i < 10; i++)
	{
		input1.push_back(i);
		input2.push_back(i+10);
	}
	xmlrpc_c::value arrayArray1 = xmlrpc_c::toValue(input1);
	xmlrpc_c::value arrayArray2 = xmlrpc_c::toValue(input2);
	xmlrpc_c::paramList paramLst1;
	paramLst1.addc(arrayArray1);
	paramLst1.addc(arrayArray2);
	xmlrpc_c::value array_result;
	myClient.call(serverUrl, "send_array", paramLst1, &array_result);
	//返回值进行处理
	std::vector<xmlrpc_c::value> send_result;
	xmlrpc_c::fromValue(send_result, array_result);
	for (int i = 0; i < send_result.size(); i++)
	{
		std::vector<xmlrpc_c::value> sub_send_result;
		xmlrpc_c::fromValue(sub_send_result, send_result[i]);
		for (int j = 0; j < sub_send_result.size(); j++)
		{
			cout << "输出参数:" << xmlrpc_c::value_int(sub_send_result[j]) << endl;
		}
		
	}
	system("pause");
	return 0;
}

客户端中演示了调用http服务的功能,使用http时代码中需要设置ip和端口号,然后直接通过调用函数的方式调用,演示了向服务端发送字符串、接收字符串数据、计算加法的示例。接收和发送中文字符串需要对字符编码进行处理,否则会出现乱码,UTF8ToGBK函数对接收到的字符串编码进行处理,StringToDword函数对发送的字符串编码进行处理,(服务端也会对接收到的字符串的编码进行处理,不处理的话服务端接收到的是乱码)

C++ 项目中包含xmlrpc的库,xmlrpc库可以参考 https://sourceforge.net/p/xmlrpc-c/code/HEAD/tree/

C++客户端和服务端输出结果

在这里插入图片描述
先运行服务端,在运行客户端,否则单独运行客户端会出错崩溃,代码中暂时没有对错误异常处理,输出的结果入截图,左边是服务端,右边是客户端,服务端中输出了客户端传入的数据,客户端中输出了服务端中返回的数据。

Python编写客户端

使用xmlrpc库进行编写,编写比较方便,代码如下,代码很简短,直接调用函数的方式调用http的服务

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from xmlrpc.client import ServerProxy

server = ServerProxy("http://localhost:8088",encoding='utf-8',allow_none=True)
#调用coding方法,打印输出结果
print(server.coding('coding'))
#调用get_connnect方法
print(server.get_connnect())
#调用add方法
print('Result of RPC (sum of 5 and 7): {}'.format(server.add(5,7)))
print('Result of RPC (sum of 1 and 2): {}'.format(server.add1({'first':1,'second':3})))
#发送集合参数
input1 = []
input2 = []
for i in range(10):
    input1.append(i)
    input2.append(i+10)
ret = server.send_array(input1,input2)
print(ret)

运行结果如下

在这里插入图片描述
截图中包含客户端和服务端的输出结果

本文章主要参考以下博客,关于xmlrpc的介绍可以在下面的的博客中找到

https://blog.csdn.net/weixin_37348409/article/details/102327255
https://blog.csdn.net/qq_28453017/article/details/79931620

文章中C++工程代码和python代码已经上传到CSDN中,具体可以查看下载链接https://download.csdn.net/download/zckui/37257772,(C++项目工程只能编译成x86、32位的,编译成64位的会出错,windows上暂不支持64位编译)

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值