背景
偶然发现rest_rpc这个项目https://github.com/qicosmos/rest_rpc,本人用Python顺手,就想办法用Python来测试之,于是有了本篇
编码
参照之前的文章准备好pybind
#include<iostream>
#include<string>
#include<unordered_map>
#define MSGPACK_DISABLE_LEGACY_NIL
#define MSGPACK_NO_BOOST
#include<rest_rpc.hpp>
#include<pybind11/pybind11.h>
#include<pybind11/functional.h>
namespace py = pybind11;
using rest_rpc::rpc_service::rpc_conn;
using rest_rpc::rpc_service::rpc_server;
using rest_rpc::rpc_client;
typedef std::function<std::string(const std::string&)> F_SS;
typedef std::function<int(const std::string&)> F_SI;
class Server {
public:
void set_handler_ss(const std::string& name, const F_SS& f) {
func_ss_map[name] = f;
}
void set_handler_si(const std::string& name, const F_SI& f) {
func_si_map[name] = f;
}
int serve(int port) {
py::gil_scoped_release release;
static rpc_server server(port, std::thread::hardware_concurrency());
for (auto& it : func_ss_map) {
server.register_handler(it.first, [&it](rpc_conn conn, const std::string& data) -> std::string {
return it.second(data);
});
}
for (auto& it : func_si_map) {
server.register_handler(it.first, [&it](rpc_conn conn, const std::string& data) -> int {
return it.second(data);
});
}
server.run();
return 0;
}
public:
std::unordered_map<std::string,F_SS> func_ss_map;
std::unordered_map<std::string,F_SI> func_si_map;
};
static std::string test_call_ss(int port, const std::string& name, const std::string& indata) {
rpc_client client("127.0.0.1", port);
if (!client.connect()) {
std::cout << "connect failed" << std::endl;
return "";
}
std::string result = client.call<std::string>(name, indata);
client.close();
return result;
}
static int test_call_si(int port, const std::string& name, const std::string& indata) {
rpc_client client("127.0.0.1", port);
if (!client.connect()) {
std::cout << "connect failed" << std::endl;
return -1;
}
int ret = client.call<int>(name, indata);
client.close();
return ret;
}
PYBIND11_MODULE(rest_rpc, m) {
py::class_<Server>(m, "Server")
.def(py::init())
.def("set_handler_ss", &Server::set_handler_ss)
.def("set_handler_si", &Server::set_handler_si)
.def("serve", &Server::serve);
m.def("test_call_ss", &test_call_ss);
m.def("test_call_si", &test_call_si);
}
注意: 此代码中默认只定义2个通用函数类型
- std::string f(const std::string& data)
- int f(const std::string& data)
为什么定义这两个函数就够了?实际参数可以通过msgpack序列化成字符串作为参数传递,这样就解决了函数任意参数的问题。而返回值无非是一个字符串,字典(又可序列化成字符串)或者整形。
编译
g++ -Iinclude -std=c++11 -lc++ -shared -undefined dynamic_lookup $(python3 -m pybind11 --includes) -DPYBIND11 restrpc_glue.cpp -o rest_rpc$(python3-config --extension-suffix)
测试
#!python3
import sys
import rest_rpc
def echo(data):
print("echo ", data)
return data
if __name__ == "__main__":
t = sys.argv[1]
if t == "server":
serv = rest_rpc.Server()
serv.set_handler_ss("echo", echo)
serv.serve(8080)
elif t == "client":
data = rest_rpc.test_call_ss(8080, "echo", "somedata")
print("recv", data)