刚学会 C++ 的小白用这个开源框架,做个 RPC 服务要多久? (2)

使用时需要先实例化一个 rpc_server 对象并提供 监听端口、线程池大小,例如:

rpc_server server(9000, 6); // 监听 9000 端口,线程池大小为 6 2)服务端注册与启动

rpc_server 提供了 register_handler 方法注册服务以及 run 方法启动服务端,具体例子如下:

/*服务函数第一个参数必须为 rpc_conn,然后才是实现功能需要的参数(为可变参数,数量可变,也可以没有*/ std::string hello(rpc_conn conn, std::string name){ /*可以为 void 返回类型,代表调用后不给远程客户端返回消息*/ return ("Hello " + name); /*返回给远程客户端的内容*/ } int main(){ rpc_server server(9000, 6); /*func_greet 为服务名,远程调用通过服务名确定调用函数*/ /*hello 为函数,绑定当前服务调用哪个函数*/ server.register_handler("func_greet", hello); server.run();//启动服务端 return EXIT_SUCCESS; }

其中 function 可以为 仿函数 或 lambda,例子分别如下:

使用仿函数

/*仿函数方法*/ struct test_func{ std::string hello(rpc_conn conn){ return "Hello Github!"; } }; int main(){ test_func greeting; rpc_server server(9000, 6); /*greet 为服务名,远程调用通过服务名确定调用函数*/ /*test_func::hello 为函数,绑定当前服务调用哪个函数*/ /*greeting 为实例化仿函数对象*/ server.register_handler("greet", &test_func::hello, &greeting); server.run();//启动服务端 return EXIT_SUCCESS; }

使用 lambda 方法的例子

/*使用 lambda 方法*/ int main(){ rpc_server server(9000, 6); /*call_lambda 为服务名,远程调用通过服务名确定调用函数*/ /*[&server](rpc_conn conn){...} 为 lambda 对象*/ server.register_handler("call_lambda", /*除 conn 外其他参数为可变参数*/ [&server](rpc_conn conn /*其他参数可有可无*/) { std::cout << "Hello Github!" << std::endl; // 返回值可有可无 }); server.run();//启动服务端 return EXIT_SUCCESS; } 3)注册异步服务

有时因为各种原因我们无法或者不希望一个远程调用能同步返回(比如需要等待一个线程返回),这时候只需给 register_handler 方法一个 Async 模板参数(位于 rest_rpc 命名空间):

/*异步服务返回类型为 void*/ void async_greet(rpc_conn conn, const std::string& name) { auto req_id = conn.lock()->request_id();// 异步服务需要先保存请求 id // 这里新建了一个线程,代表异步处理了一些任务 std::thread thd([conn, req_id, name] { std::string ret = "Hello " + name + ", Welcome to Hello Github!"; /*这里的 conn 是一个 weak_ptr*/ auto conn_sp = conn.lock();// 使用 weak_ptr 的 lock 方法获取一个 shared_ptr if (conn_sp) { /*操作完成,返回;std::move(ret) 为返回值*/ conn_sp->pack_and_response(req_id, std::move(ret)); } }); thd.detach(); } int main(){ rpc_server server(9000, 6); server.register_handler<Async>("async_greet", async_greet);// 使用 Async 作为模板参数 server.run();//启动服务端 return EXIT_SUCCESS; }

rest_rpc 支持在同一个端口上注册多个服务,例如:

server.register_handler("func_greet", hello); server.register_handler("greet", &test_func::hello, &greeting); server.register_handler("call_lambda", /*除 conn 外其他参数为可变参数*/ [&server](rpc_conn conn /*其他参数可有可无*/) { std::cout << "Hello Github!" << std::endl; // 返回值可有可无 }); // 其他服务等等 server.run(); 3.3 编写客户端

生成一个能进行远程服务调用的客户端要经历以下过程:

rpc_client 对象实例化,设定服务端地址与端口

连接服务端

调用服务

1)rpc_client

rpc_client 为 rest_rpc 客户端对象,有连接服务端、调用服务端服务、序列化消息、反序列化消息等功能,位于 rest_rpc 命名空间。

使用时需要先实例化一个 rpc_client 对象,然后使用其提供的 connect 或 async_connect 方法来 同步/异步 的连接到服务器,如:

rpc_client client; bool has_connected = client.connect("127.0.0.1", 9000);//同步连接,返回是否连接成功 client.async_connect("127.0.0.1", 9000);//异步连接,无返回值

当然,rpc_client 还提供了 enable_auto_reconnect 和 enable_auto_heartbeat 功能,用于不同情况下保持连接。

2)调用远程服务

rpc_client 提供了 async_call 和 call 两种方式来 异步/同步 的调用远程服务,其中 async_call 又支持 callback 和 future 两种处理返回消息的方法,这部分介绍 同步 调用方法 call。

在调用 call 方法时如果我们的服务有返回值则需要设定模板参数,比如远程服务返回一个整数需要这样指定返回值类型 call<int>,如果不指定则代表无返回值。

编写服务端 部分我们说过每个服务在注册的时候都有一个名字,通过名字可以进行远程服务的调用,现在我们调用 服务端 部分写的第一个例子:

int main(){ /* rest_rpc 在遇到错误(调用服务传入参数和远程服务需要参数不一致、连接失败等)时会抛出异常*/ try{ /*建立连接*/ rpc_client client("127.0.0.1", 9000);// IP 地址,端口号 /*设定超时 5s(不填默认为 3s),connect 超时返回 false,成功返回 true*/ bool has_connected = client.connect(5); /*没有建立连接则退出程序*/ if (!has_connected) { std::cout << "connect timeout" << std::endl; exit(-1); } /*调用远程服务,返回欢迎信息*/ std::string result = client.call<std::string>("func_greet", "HG");// func_greet 为事先注册好的服务名,需要一个 name 参数,这里为 Hello Github 的缩写 HG std::cout << result << std::endl; } /*遇到连接错误、调用服务时参数不对等情况会抛出异常*/ catch (const std::exception & e) { std::cout << e.what() << std::endl; } return EXIT_SUCCESS; }

当然,有些调用也许没有任何消息返回,这是时候直接使用 client.call("xxx", ...) 即可,此时 call 方法返回类型为 void。

3)异步调用远程服务

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgpdy.html