initial commit
This commit is contained in:
79
third_party/libhv/examples/protorpc/handler/calc.h
vendored
Executable file
79
third_party/libhv/examples/protorpc/handler/calc.h
vendored
Executable file
@@ -0,0 +1,79 @@
|
||||
#ifndef HV_PROTO_RPC_HANDLER_CALC_H_
|
||||
#define HV_PROTO_RPC_HANDLER_CALC_H_
|
||||
|
||||
#include "../router.h"
|
||||
|
||||
#include "../generated/calc.pb.h"
|
||||
|
||||
void calc_add(const protorpc::Request& req, protorpc::Response* res) {
|
||||
// params
|
||||
if (req.params_size() != 2) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
protorpc::CalcParam param1, param2;
|
||||
if (!param1.ParseFromString(req.params(0)) ||
|
||||
!param2.ParseFromString(req.params(1))) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
|
||||
// result
|
||||
protorpc::CalcResult result;
|
||||
result.set_num(param1.num() + param2.num());
|
||||
res->set_result(result.SerializeAsString());
|
||||
}
|
||||
|
||||
void calc_sub(const protorpc::Request& req, protorpc::Response* res) {
|
||||
// params
|
||||
if (req.params_size() != 2) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
protorpc::CalcParam param1, param2;
|
||||
if (!param1.ParseFromString(req.params(0)) ||
|
||||
!param2.ParseFromString(req.params(1))) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
|
||||
// result
|
||||
protorpc::CalcResult result;
|
||||
result.set_num(param1.num() - param2.num());
|
||||
res->set_result(result.SerializeAsString());
|
||||
}
|
||||
|
||||
void calc_mul(const protorpc::Request& req, protorpc::Response* res) {
|
||||
// params
|
||||
if (req.params_size() != 2) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
protorpc::CalcParam param1, param2;
|
||||
if (!param1.ParseFromString(req.params(0)) ||
|
||||
!param2.ParseFromString(req.params(1))) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
|
||||
// result
|
||||
protorpc::CalcResult result;
|
||||
result.set_num(param1.num() * param2.num());
|
||||
res->set_result(result.SerializeAsString());
|
||||
}
|
||||
|
||||
void calc_div(const protorpc::Request& req, protorpc::Response* res) {
|
||||
// params
|
||||
if (req.params_size() != 2) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
protorpc::CalcParam param1, param2;
|
||||
if (!param1.ParseFromString(req.params(0)) ||
|
||||
!param2.ParseFromString(req.params(1))) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
if (param2.num() == 0) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
|
||||
// result
|
||||
protorpc::CalcResult result;
|
||||
result.set_num(param1.num() / param2.num());
|
||||
res->set_result(result.SerializeAsString());
|
||||
}
|
||||
|
||||
#endif // HV_PROTO_RPC_HANDLER_CALC_H_
|
||||
19
third_party/libhv/examples/protorpc/handler/handler.h
vendored
Executable file
19
third_party/libhv/examples/protorpc/handler/handler.h
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
#ifndef HV_PROTO_RPC_HANDLER_H_
|
||||
#define HV_PROTO_RPC_HANDLER_H_
|
||||
|
||||
#include "../router.h"
|
||||
|
||||
void error_response(protorpc::Response* res, int code, const std::string& message) {
|
||||
res->mutable_error()->set_code(code);
|
||||
res->mutable_error()->set_message(message);
|
||||
}
|
||||
|
||||
void not_found(const protorpc::Request& req, protorpc::Response* res) {
|
||||
error_response(res, 404, "Not Found");
|
||||
}
|
||||
|
||||
void bad_request(const protorpc::Request& req, protorpc::Response* res) {
|
||||
error_response(res, 400, "Bad Request");
|
||||
}
|
||||
|
||||
#endif // HV_PROTO_RPC_HANDLER_H_
|
||||
25
third_party/libhv/examples/protorpc/handler/login.h
vendored
Executable file
25
third_party/libhv/examples/protorpc/handler/login.h
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
#ifndef HV_PROTO_RPC_HANDLER_LOGIN_H_
|
||||
#define HV_PROTO_RPC_HANDLER_LOGIN_H_
|
||||
|
||||
#include "../router.h"
|
||||
|
||||
#include "../generated/login.pb.h"
|
||||
|
||||
void login(const protorpc::Request& req, protorpc::Response* res) {
|
||||
// params
|
||||
if (req.params_size() == 0) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
protorpc::LoginParam param;
|
||||
if (!param.ParseFromString(req.params(0))) {
|
||||
return bad_request(req, res);
|
||||
}
|
||||
|
||||
// result
|
||||
protorpc::LoginResult result;
|
||||
result.set_user_id(123456);
|
||||
result.set_token(param.username() + ":" + param.password());
|
||||
res->set_result(result.SerializeAsString());
|
||||
}
|
||||
|
||||
#endif // HV_PROTO_RPC_HANDLER_LOGIN_H_
|
||||
20
third_party/libhv/examples/protorpc/proto/base.proto
vendored
Executable file
20
third_party/libhv/examples/protorpc/proto/base.proto
vendored
Executable file
@@ -0,0 +1,20 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package protorpc;
|
||||
|
||||
message Error {
|
||||
int32 code = 1;
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
message Request {
|
||||
uint64 id = 1;
|
||||
string method = 2;
|
||||
repeated bytes params = 3;
|
||||
}
|
||||
|
||||
message Response {
|
||||
uint64 id = 1;
|
||||
bytes result = 2;
|
||||
Error error = 3;
|
||||
}
|
||||
11
third_party/libhv/examples/protorpc/proto/calc.proto
vendored
Executable file
11
third_party/libhv/examples/protorpc/proto/calc.proto
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package protorpc;
|
||||
|
||||
message CalcParam {
|
||||
int64 num = 1;
|
||||
}
|
||||
|
||||
message CalcResult {
|
||||
int64 num = 1;
|
||||
}
|
||||
13
third_party/libhv/examples/protorpc/proto/login.proto
vendored
Executable file
13
third_party/libhv/examples/protorpc/proto/login.proto
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package protorpc;
|
||||
|
||||
message LoginParam {
|
||||
string username = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
message LoginResult {
|
||||
uint64 user_id = 1;
|
||||
string token = 2;
|
||||
}
|
||||
18
third_party/libhv/examples/protorpc/proto/protoc.sh
vendored
Executable file
18
third_party/libhv/examples/protorpc/proto/protoc.sh
vendored
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
PROTOC=`which protoc`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Not found command protoc!"
|
||||
echo "Please install libprotobuf first!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CPP_OUT_DIR=../generated
|
||||
if [ ! -d "${CPP_OUT_DIR}" ]; then
|
||||
mkdir -p ${CPP_OUT_DIR}
|
||||
fi
|
||||
|
||||
set -x
|
||||
${PROTOC} --cpp_out=${CPP_OUT_DIR} *.proto
|
||||
65
third_party/libhv/examples/protorpc/protorpc.c
vendored
Executable file
65
third_party/libhv/examples/protorpc/protorpc.c
vendored
Executable file
@@ -0,0 +1,65 @@
|
||||
#include "protorpc.h"
|
||||
|
||||
#include <string.h> // import memcpy
|
||||
|
||||
int protorpc_pack(const protorpc_message* msg, void* buf, int len) {
|
||||
if (!msg || !buf || !len) return -1;
|
||||
const protorpc_head* head = &(msg->head);
|
||||
unsigned int packlen = protorpc_package_length(head);
|
||||
// Check is buffer enough
|
||||
if (len < packlen) {
|
||||
return -2;
|
||||
}
|
||||
unsigned char* p = (unsigned char*)buf;
|
||||
*p++ = head->protocol[0];
|
||||
*p++ = head->protocol[1];
|
||||
*p++ = head->protocol[2];
|
||||
*p++ = head->protocol[3];
|
||||
*p++ = head->version;
|
||||
*p++ = head->flags;
|
||||
*p++ = head->reserved[0];
|
||||
*p++ = head->reserved[1];
|
||||
// hton length
|
||||
unsigned int length = head->length;
|
||||
*p++ = (length >> 24) & 0xFF;
|
||||
*p++ = (length >> 16) & 0xFF;
|
||||
*p++ = (length >> 8) & 0xFF;
|
||||
*p++ = length & 0xFF;
|
||||
// memcpy body
|
||||
if (msg->body && head->length) {
|
||||
memcpy(p, msg->body, head->length);
|
||||
}
|
||||
|
||||
return packlen;
|
||||
}
|
||||
|
||||
int protorpc_unpack(protorpc_message* msg, const void* buf, int len) {
|
||||
if (!msg || !buf || !len) return -1;
|
||||
if (len < PROTORPC_HEAD_LENGTH) return -2;
|
||||
protorpc_head* head = &(msg->head);
|
||||
const unsigned char* p = (const unsigned char*)buf;
|
||||
head->protocol[0] = *p++;
|
||||
head->protocol[1] = *p++;
|
||||
head->protocol[2] = *p++;
|
||||
head->protocol[3] = *p++;
|
||||
head->version = *p++;
|
||||
head->flags = *p++;
|
||||
head->reserved[0] = *p++;
|
||||
head->reserved[1] = *p++;
|
||||
// ntoh length
|
||||
head->length = ((unsigned int)*p++) << 24;
|
||||
head->length |= ((unsigned int)*p++) << 16;
|
||||
head->length |= ((unsigned int)*p++) << 8;
|
||||
head->length |= *p++;
|
||||
// Check is buffer enough
|
||||
unsigned int packlen = protorpc_package_length(head);
|
||||
if (len < packlen) {
|
||||
return -3;
|
||||
}
|
||||
// NOTE: just shadow copy
|
||||
if (len > PROTORPC_HEAD_LENGTH) {
|
||||
msg->body = (const char*)buf + PROTORPC_HEAD_LENGTH;
|
||||
}
|
||||
|
||||
return packlen;
|
||||
}
|
||||
68
third_party/libhv/examples/protorpc/protorpc.h
vendored
Executable file
68
third_party/libhv/examples/protorpc/protorpc.h
vendored
Executable file
@@ -0,0 +1,68 @@
|
||||
#ifndef HV_PROTO_RPC_H_
|
||||
#define HV_PROTO_RPC_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PROTORPC_NAME "HRPC"
|
||||
#define PROTORPC_VERSION 1
|
||||
|
||||
// protocol:4bytes + version:1byte + flags:1byte + reserved:2bytes + length:4bytes = 12bytes
|
||||
#define PROTORPC_HEAD_LENGTH 12
|
||||
#define PROTORPC_HEAD_LENGTH_FIELD_OFFSET 8
|
||||
#define PROTORPC_HEAD_LENGTH_FIELD_BYTES 4
|
||||
typedef struct {
|
||||
unsigned char protocol[4];
|
||||
unsigned char version;
|
||||
unsigned char flags;
|
||||
unsigned char reserved[2];
|
||||
unsigned int length;
|
||||
} protorpc_head;
|
||||
|
||||
typedef const char* protorpc_body;
|
||||
|
||||
typedef struct {
|
||||
protorpc_head head;
|
||||
protorpc_body body;
|
||||
} protorpc_message;
|
||||
|
||||
static inline unsigned int protorpc_package_length(const protorpc_head* head) {
|
||||
return PROTORPC_HEAD_LENGTH + head->length;
|
||||
}
|
||||
|
||||
static inline void protorpc_head_init(protorpc_head* head) {
|
||||
// protocol = HRPC
|
||||
memcpy(head->protocol, PROTORPC_NAME, 4);
|
||||
head->version = PROTORPC_VERSION;
|
||||
head->reserved[0] = head->reserved[1] = 0;
|
||||
head->length = 0;
|
||||
}
|
||||
|
||||
static inline void protorpc_message_init(protorpc_message* msg) {
|
||||
protorpc_head_init(&msg->head);
|
||||
msg->body = NULL;
|
||||
}
|
||||
|
||||
static inline int protorpc_head_check(protorpc_head* head) {
|
||||
if (memcmp(head->protocol, PROTORPC_NAME, 4) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (head->version != PROTORPC_VERSION) {
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// @retval >0 package_length, <0 error
|
||||
int protorpc_pack(const protorpc_message* msg, void* buf, int len);
|
||||
// @retval >0 package_length, <0 error
|
||||
int protorpc_unpack(protorpc_message* msg, const void* buf, int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // HV_PROTO_RPC_H_
|
||||
280
third_party/libhv/examples/protorpc/protorpc_client.cpp
vendored
Executable file
280
third_party/libhv/examples/protorpc/protorpc_client.cpp
vendored
Executable file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* proto rpc client
|
||||
*
|
||||
* @build make protorpc
|
||||
* @server bin/protorpc_server 1234
|
||||
* @client bin/protorpc_client 127.0.0.1 1234 add 1 2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TcpClient.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
using namespace hv;
|
||||
|
||||
#include "protorpc.h"
|
||||
#include "generated/base.pb.h"
|
||||
#include "generated/calc.pb.h"
|
||||
#include "generated/login.pb.h"
|
||||
|
||||
// valgrind --leak-check=full --show-leak-kinds=all
|
||||
class ProtobufRAII {
|
||||
public:
|
||||
ProtobufRAII() {
|
||||
}
|
||||
~ProtobufRAII() {
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
}
|
||||
};
|
||||
static ProtobufRAII s_protobuf;
|
||||
|
||||
namespace protorpc {
|
||||
typedef std::shared_ptr<protorpc::Request> RequestPtr;
|
||||
typedef std::shared_ptr<protorpc::Response> ResponsePtr;
|
||||
|
||||
enum ProtoRpcResult {
|
||||
kRpcSuccess = 0,
|
||||
kRpcTimeout = -1,
|
||||
kRpcError = -2,
|
||||
kRpcNoResult = -3,
|
||||
kRpcParseError = -4,
|
||||
};
|
||||
|
||||
class ProtoRpcContext {
|
||||
public:
|
||||
protorpc::RequestPtr req;
|
||||
protorpc::ResponsePtr res;
|
||||
private:
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _cond;
|
||||
|
||||
public:
|
||||
void wait(int timeout_ms) {
|
||||
std::unique_lock<std::mutex> locker(_mutex);
|
||||
_cond.wait_for(locker, std::chrono::milliseconds(timeout_ms));
|
||||
}
|
||||
|
||||
void notify() {
|
||||
_cond.notify_one();
|
||||
}
|
||||
};
|
||||
typedef std::shared_ptr<ProtoRpcContext> ContextPtr;
|
||||
|
||||
class ProtoRpcClient : public TcpClient {
|
||||
public:
|
||||
ProtoRpcClient() : TcpClient()
|
||||
{
|
||||
connect_state = kInitialized;
|
||||
|
||||
setConnectTimeout(5000);
|
||||
|
||||
reconn_setting_t reconn;
|
||||
reconn_setting_init(&reconn);
|
||||
reconn.min_delay = 1000;
|
||||
reconn.max_delay = 10000;
|
||||
reconn.delay_policy = 2;
|
||||
setReconnect(&reconn);
|
||||
|
||||
// init protorpc_unpack_setting
|
||||
unpack_setting_t protorpc_unpack_setting;
|
||||
memset(&protorpc_unpack_setting, 0, sizeof(unpack_setting_t));
|
||||
protorpc_unpack_setting.mode = UNPACK_BY_LENGTH_FIELD;
|
||||
protorpc_unpack_setting.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
|
||||
protorpc_unpack_setting.body_offset = PROTORPC_HEAD_LENGTH;
|
||||
protorpc_unpack_setting.length_field_offset = PROTORPC_HEAD_LENGTH_FIELD_OFFSET;
|
||||
protorpc_unpack_setting.length_field_bytes = PROTORPC_HEAD_LENGTH_FIELD_BYTES;
|
||||
protorpc_unpack_setting.length_field_coding = ENCODE_BY_BIG_ENDIAN;
|
||||
setUnpack(&protorpc_unpack_setting);
|
||||
|
||||
onConnection = [this](const SocketChannelPtr& channel) {
|
||||
std::string peeraddr = channel->peeraddr();
|
||||
if (channel->isConnected()) {
|
||||
connect_state = kConnected;
|
||||
printf("connected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||
} else {
|
||||
connect_state = kDisconnectd;
|
||||
printf("disconnected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||
}
|
||||
};
|
||||
|
||||
onMessage = [this](const SocketChannelPtr& channel, Buffer* buf) {
|
||||
// protorpc_unpack
|
||||
protorpc_message msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
int packlen = protorpc_unpack(&msg, buf->data(), buf->size());
|
||||
if (packlen < 0) {
|
||||
printf("protorpc_unpack failed!\n");
|
||||
return;
|
||||
}
|
||||
assert(packlen == buf->size());
|
||||
if (protorpc_head_check(&msg.head) != 0) {
|
||||
printf("protorpc_head_check failed!\n");
|
||||
return;
|
||||
}
|
||||
// Response::ParseFromArray
|
||||
auto res = std::make_shared<protorpc::Response>();
|
||||
if (!res->ParseFromArray(msg.body, msg.head.length)) {
|
||||
return;
|
||||
}
|
||||
// id => res
|
||||
calls_mutex.lock();
|
||||
auto iter = calls.find(res->id());
|
||||
if (iter == calls.end()) {
|
||||
calls_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
auto ctx = iter->second;
|
||||
calls_mutex.unlock();
|
||||
ctx->res = res;
|
||||
ctx->notify();
|
||||
};
|
||||
}
|
||||
|
||||
int connect(int port, const char* host = "127.0.0.1") {
|
||||
createsocket(port, host);
|
||||
connect_state = kConnecting;
|
||||
start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protorpc::ResponsePtr call(protorpc::RequestPtr& req, int timeout_ms = 10000) {
|
||||
if (connect_state != kConnected) {
|
||||
return NULL;
|
||||
}
|
||||
static std::atomic<uint64_t> s_id = ATOMIC_VAR_INIT(0);
|
||||
req->set_id(++s_id);
|
||||
req->id();
|
||||
auto ctx = std::make_shared<protorpc::ProtoRpcContext>();
|
||||
ctx->req = req;
|
||||
calls_mutex.lock();
|
||||
calls[req->id()] = ctx;
|
||||
calls_mutex.unlock();
|
||||
// Request::SerializeToArray + protorpc_pack
|
||||
protorpc_message msg;
|
||||
protorpc_message_init(&msg);
|
||||
msg.head.length = req->ByteSize();
|
||||
int packlen = protorpc_package_length(&msg.head);
|
||||
unsigned char* writebuf = NULL;
|
||||
HV_STACK_ALLOC(writebuf, packlen);
|
||||
packlen = protorpc_pack(&msg, writebuf, packlen);
|
||||
if (packlen > 0) {
|
||||
printf("%s\n", req->DebugString().c_str());
|
||||
req->SerializeToArray(writebuf + PROTORPC_HEAD_LENGTH, msg.head.length);
|
||||
channel->write(writebuf, packlen);
|
||||
}
|
||||
HV_STACK_FREE(writebuf);
|
||||
// wait until response come or timeout
|
||||
ctx->wait(timeout_ms);
|
||||
auto res = ctx->res;
|
||||
calls_mutex.lock();
|
||||
calls.erase(req->id());
|
||||
calls_mutex.unlock();
|
||||
if (res == NULL) {
|
||||
printf("RPC timeout!\n");
|
||||
} else if (res->has_error()) {
|
||||
printf("RPC error:\n%s\n", res->error().DebugString().c_str());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int calc(const char* method, int num1, int num2, int& out) {
|
||||
auto req = std::make_shared<protorpc::Request>();
|
||||
// method
|
||||
req->set_method(method);
|
||||
// params
|
||||
protorpc::CalcParam param1, param2;
|
||||
param1.set_num(num1);
|
||||
param2.set_num(num2);
|
||||
req->add_params()->assign(param1.SerializeAsString());
|
||||
req->add_params()->assign(param2.SerializeAsString());
|
||||
|
||||
auto res = call(req);
|
||||
|
||||
if (res == NULL) return kRpcTimeout;
|
||||
if (res->has_error()) return kRpcError;
|
||||
if (res->result().empty()) return kRpcNoResult;
|
||||
protorpc::CalcResult result;
|
||||
if (!result.ParseFromString(res->result())) return kRpcParseError;
|
||||
out = result.num();
|
||||
return kRpcSuccess;
|
||||
}
|
||||
|
||||
int login(const protorpc::LoginParam& param, protorpc::LoginResult* result) {
|
||||
auto req = std::make_shared<protorpc::Request>();
|
||||
// method
|
||||
req->set_method("login");
|
||||
// params
|
||||
req->add_params()->assign(param.SerializeAsString());
|
||||
|
||||
auto res = call(req);
|
||||
|
||||
if (res == NULL) return kRpcTimeout;
|
||||
if (res->has_error()) return kRpcError;
|
||||
if (res->result().empty()) return kRpcNoResult;
|
||||
if (!result->ParseFromString(res->result())) return kRpcParseError;
|
||||
return kRpcSuccess;
|
||||
}
|
||||
|
||||
enum {
|
||||
kInitialized,
|
||||
kConnecting,
|
||||
kConnected,
|
||||
kDisconnectd,
|
||||
} connect_state;
|
||||
std::map<uint64_t, protorpc::ContextPtr> calls;
|
||||
std::mutex calls_mutex;
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 6) {
|
||||
printf("Usage: %s host port method param1 param2\n", argv[0]);
|
||||
printf("method = [add, sub, mul, div]\n");
|
||||
printf("Examples:\n");
|
||||
printf(" %s 127.0.0.1 1234 add 1 2\n", argv[0]);
|
||||
printf(" %s 127.0.0.1 1234 div 1 0\n", argv[0]);
|
||||
return -10;
|
||||
}
|
||||
const char* host = argv[1];
|
||||
int port = atoi(argv[2]);
|
||||
const char* method = argv[3];
|
||||
const char* param1 = argv[4];
|
||||
const char* param2 = argv[5];
|
||||
|
||||
protorpc::ProtoRpcClient cli;
|
||||
cli.connect(port, host);
|
||||
while (cli.connect_state == protorpc::ProtoRpcClient::kConnecting) hv_msleep(1);
|
||||
if (cli.connect_state == protorpc::ProtoRpcClient::kDisconnectd) {
|
||||
return -20;
|
||||
}
|
||||
|
||||
// test login
|
||||
{
|
||||
protorpc::LoginParam param;
|
||||
param.set_username("admin");
|
||||
param.set_password("123456");
|
||||
protorpc::LoginResult result;
|
||||
if (cli.login(param, &result) == protorpc::kRpcSuccess) {
|
||||
printf("login success!\n");
|
||||
printf("%s\n", result.DebugString().c_str());
|
||||
} else {
|
||||
printf("login failed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// test calc
|
||||
{
|
||||
int num1 = atoi(param1);
|
||||
int num2 = atoi(param2);
|
||||
int result = 0;
|
||||
if (cli.calc(method, num1, num2, result) == protorpc::kRpcSuccess) {
|
||||
printf("calc success!\n");
|
||||
printf("%d %s %d = %d\n", num1, method, num2, result);
|
||||
} else {
|
||||
printf("calc failed!\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
141
third_party/libhv/examples/protorpc/protorpc_server.cpp
vendored
Executable file
141
third_party/libhv/examples/protorpc/protorpc_server.cpp
vendored
Executable file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* proto rpc server
|
||||
*
|
||||
* @build make protorpc
|
||||
* @server bin/protorpc_server 1234
|
||||
* @client bin/protorpc_client 127.0.0.1 1234 add 1 2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TcpServer.h"
|
||||
|
||||
using namespace hv;
|
||||
|
||||
#include "protorpc.h"
|
||||
#include "router.h"
|
||||
#include "handler/handler.h"
|
||||
#include "handler/calc.h"
|
||||
#include "handler/login.h"
|
||||
|
||||
// valgrind --leak-check=full --show-leak-kinds=all
|
||||
class ProtobufRAII {
|
||||
public:
|
||||
ProtobufRAII() {
|
||||
}
|
||||
~ProtobufRAII() {
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
}
|
||||
};
|
||||
static ProtobufRAII s_protobuf;
|
||||
|
||||
protorpc_router router[] = {
|
||||
{"add", calc_add},
|
||||
{"sub", calc_sub},
|
||||
{"mul", calc_mul},
|
||||
{"div", calc_div},
|
||||
{"login", login},
|
||||
};
|
||||
#define PROTORPC_ROUTER_NUM (sizeof(router)/sizeof(router[0]))
|
||||
|
||||
class ProtoRpcServer : public TcpServer {
|
||||
public:
|
||||
ProtoRpcServer() : TcpServer()
|
||||
{
|
||||
onConnection = [](const SocketChannelPtr& channel) {
|
||||
std::string peeraddr = channel->peeraddr();
|
||||
if (channel->isConnected()) {
|
||||
printf("%s connected! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||
} else {
|
||||
printf("%s disconnected! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||
}
|
||||
};
|
||||
onMessage = handleMessage;
|
||||
// init protorpc_unpack_setting
|
||||
unpack_setting_t protorpc_unpack_setting;
|
||||
memset(&protorpc_unpack_setting, 0, sizeof(unpack_setting_t));
|
||||
protorpc_unpack_setting.mode = UNPACK_BY_LENGTH_FIELD;
|
||||
protorpc_unpack_setting.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
|
||||
protorpc_unpack_setting.body_offset = PROTORPC_HEAD_LENGTH;
|
||||
protorpc_unpack_setting.length_field_offset = PROTORPC_HEAD_LENGTH_FIELD_OFFSET;
|
||||
protorpc_unpack_setting.length_field_bytes = PROTORPC_HEAD_LENGTH_FIELD_BYTES;
|
||||
protorpc_unpack_setting.length_field_coding = ENCODE_BY_BIG_ENDIAN;
|
||||
setUnpack(&protorpc_unpack_setting);
|
||||
}
|
||||
|
||||
int listen(int port) { return createsocket(port); }
|
||||
|
||||
private:
|
||||
static void handleMessage(const SocketChannelPtr& channel, Buffer* buf) {
|
||||
// unpack -> Request::ParseFromArray -> router -> Response::SerializeToArray -> pack -> Channel::write
|
||||
// protorpc_unpack
|
||||
protorpc_message msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
int packlen = protorpc_unpack(&msg, buf->data(), buf->size());
|
||||
if (packlen < 0) {
|
||||
printf("protorpc_unpack failed!\n");
|
||||
return;
|
||||
}
|
||||
assert(packlen == buf->size());
|
||||
if (protorpc_head_check(&msg.head) != 0) {
|
||||
printf("protorpc_head_check failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Request::ParseFromArray
|
||||
protorpc::Request req;
|
||||
protorpc::Response res;
|
||||
if (req.ParseFromArray(msg.body, msg.head.length)) {
|
||||
printf("> %s\n", req.DebugString().c_str());
|
||||
res.set_id(req.id());
|
||||
// router
|
||||
const char* method = req.method().c_str();
|
||||
bool found = false;
|
||||
for (int i = 0; i < PROTORPC_ROUTER_NUM; ++i) {
|
||||
if (strcmp(method, router[i].method) == 0) {
|
||||
found = true;
|
||||
router[i].handler(req, &res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
not_found(req, &res);
|
||||
}
|
||||
} else {
|
||||
bad_request(req, &res);
|
||||
}
|
||||
|
||||
// Response::SerializeToArray + protorpc_pack
|
||||
protorpc_message_init(&msg);
|
||||
msg.head.length = res.ByteSize();
|
||||
packlen = protorpc_package_length(&msg.head);
|
||||
unsigned char* writebuf = NULL;
|
||||
HV_STACK_ALLOC(writebuf, packlen);
|
||||
packlen = protorpc_pack(&msg, writebuf, packlen);
|
||||
if (packlen > 0) {
|
||||
printf("< %s\n", res.DebugString().c_str());
|
||||
res.SerializeToArray(writebuf + PROTORPC_HEAD_LENGTH, msg.head.length);
|
||||
channel->write(writebuf, packlen);
|
||||
}
|
||||
HV_STACK_FREE(writebuf);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s port\n", argv[0]);
|
||||
return -10;
|
||||
}
|
||||
int port = atoi(argv[1]);
|
||||
|
||||
ProtoRpcServer srv;
|
||||
int listenfd = srv.listen(port);
|
||||
if (listenfd < 0) {
|
||||
return -20;
|
||||
}
|
||||
printf("protorpc_server listen on port %d, listenfd=%d ...\n", port, listenfd);
|
||||
srv.setThreadNum(4);
|
||||
srv.start();
|
||||
|
||||
while (1) hv_sleep(1);
|
||||
return 0;
|
||||
}
|
||||
24
third_party/libhv/examples/protorpc/router.h
vendored
Executable file
24
third_party/libhv/examples/protorpc/router.h
vendored
Executable file
@@ -0,0 +1,24 @@
|
||||
#ifndef HV_PROTO_RPC_ROUTER_H_
|
||||
#define HV_PROTO_RPC_ROUTER_H_
|
||||
|
||||
#include "generated/base.pb.h"
|
||||
|
||||
typedef void (*protorpc_handler)(const protorpc::Request& req, protorpc::Response* res);
|
||||
|
||||
typedef struct {
|
||||
const char* method;
|
||||
protorpc_handler handler;
|
||||
} protorpc_router;
|
||||
|
||||
void error_response(protorpc::Response* res, int code, const std::string& message);
|
||||
void not_found(const protorpc::Request& req, protorpc::Response* res);
|
||||
void bad_request(const protorpc::Request& req, protorpc::Response* res);
|
||||
|
||||
void calc_add(const protorpc::Request& req, protorpc::Response* res);
|
||||
void calc_sub(const protorpc::Request& req, protorpc::Response* res);
|
||||
void calc_mul(const protorpc::Request& req, protorpc::Response* res);
|
||||
void calc_div(const protorpc::Request& req, protorpc::Response* res);
|
||||
|
||||
void login(const protorpc::Request& req, protorpc::Response* res);
|
||||
|
||||
#endif // HV_PROTO_RPC_ROUTER_H_
|
||||
Reference in New Issue
Block a user