protobuf入门实践2

如何在proto中定义一个rpc服务?

syntax = "proto3"; //声明protobuf的版本

package fixbug;   //声明了代码所在的包 (对于C++来说就是namespace)


//下面的选项,表示生成service服务类和rpc方法描述, 默认是不生成的
option cc_generic_services = true;


message ResultCode{  //定义返回的错误码
    int32 errcode = 1;
    bytes errmsg = 2;
}


//常用的数据类型: 数据、列表、映射表

//定义登录请求消息类型   name   pwd
message LoginRequest{
    bytes name = 1;   //等于1表示这是第一个参数,一般string的存储定义为bytes
    bytes pwd = 2;
   // map<int32,string> test = 3; //映射表类型
}

//定义登录响应消息类型
message LoginResponse{
    ResultCode result = 1;
    bool success = 3;
}

message GetFriendsListRequest{
    uint32 user_id = 1;
}

message User{
    bytes name = 1;
    uint32 age = 2;
    enum Sex{
        MAN = 0;
        WOMAN = 1;
    }
    Sex sex = 3;
}

message GetFriendsListResponse{
    ResultCode result = 1;
    repeated User friend_list = 2;  //定义了一个列表数据类型
}


//在protobuf里面怎么定义描述rpc方法的类型---service
service UserService{
    rpc Login(LoginRequest) returns(LoginResponse);
    rpc GetFriendsList(GetFriendsListRequest) returns(GetFriendsListResponse); 
}

关键字service用于定义rpc服务,例如Userservice有两个rpc服务,分别是Login和GetFriendsList, 返回值分别就是上述定义的消息类型。
老样子,先执行protoc xxx.proto --cpp_out=./ 生成对应的xxx.pb.cc 和 xxx.pb.h文件。
需要注意的是选项option cc_generic_services = true;得加上,默认是不生成的。
这边来分析xxx.pb.h文件,简单探究一下rpc调用过程:

//!!!!xxx.pb.h
class UserService : public ::PROTOBUF_NAMESPACE_ID::Service {
 protected:
  // This class should be treated as an abstract interface.
  inline UserService() {};
 public:
  virtual ~UserService();

  typedef UserService_Stub Stub;

  static const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* descriptor();

  virtual void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done);
  virtual void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::fixbug::GetFriendsListRequest* request,
                       ::fixbug::GetFriendsListResponse* response,
                       ::google::protobuf::Closure* done);

  // implements Service ----------------------------------------------

  const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* GetDescriptor();
  void CallMethod(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method,
                  ::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                  const ::PROTOBUF_NAMESPACE_ID::Message* request,
                  ::PROTOBUF_NAMESPACE_ID::Message* response,
                  ::google::protobuf::Closure* done);
  const ::PROTOBUF_NAMESPACE_ID::Message& GetRequestPrototype(
    const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;
  const ::PROTOBUF_NAMESPACE_ID::Message& GetResponsePrototype(
    const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserService);
};
//!!!!xxx.pb.cc
void UserService::Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                         const ::fixbug::LoginRequest*,
                         ::fixbug::LoginResponse*,
                         ::google::protobuf::Closure* done) {
  controller->SetFailed("Method Login() not implemented.");
  done->Run();
}

void UserService::GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                         const ::fixbug::GetFriendsListRequest*,
                         ::fixbug::GetFriendsListResponse*,
                         ::google::protobuf::Closure* done) {
  controller->SetFailed("Method GetFriendsList() not implemented.");
  done->Run();
}

可以看到一个UserService这个类,这个和message关键字有异曲同工之妙,都是对应的一个类,只不过继承的基类是有所不同的, message消息类型继承于抽象类message, service服务类型继承于抽象类service。此外可以发现在类中实现了在proto文件中定义的两个rpc方法Login和GetFriendsList, 其中两个参数是很熟悉的,request和response,也即这个rpc方法的需要用到的调用参数,类型message基类指针,表示可以接受任意消息类型。
由此可知UserService类是一个服务提供者(Callee)

再来看另一个类

//!!!!xxx.pb.h
class UserService_Stub : public UserService {
 public:
  UserService_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel);
  UserService_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel,
                   ::PROTOBUF_NAMESPACE_ID::Service::ChannelOwnership ownership);
  ~UserService_Stub();

  inline ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel() { return channel_; }

  // implements UserService ------------------------------------------

  void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done);
  void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::fixbug::GetFriendsListRequest* request,
                       ::fixbug::GetFriendsListResponse* response,
                       ::google::protobuf::Closure* done);
 private:
  ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel_;
  bool owns_channel_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserService_Stub);

//!!!!xxx.pb.cc
void UserService_Stub::Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                              const ::fixbug::LoginRequest* request,
                              ::fixbug::LoginResponse* response,
                              ::google::protobuf::Closure* done) {
  channel_->CallMethod(descriptor()->method(0),
                       controller, request, response, done);
}
void UserService_Stub::GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                              const ::fixbug::GetFriendsListRequest* request,
                              ::fixbug::GetFriendsListResponse* response,
                              ::google::protobuf::Closure* done) {
  channel_->CallMethod(descriptor()->method(1),
                       controller, request, response, done);
}

可以看见这个类没有无参构造,有几个RpcChannel*参数传递的构造方法,,不妨看看RpcChannel类:

class PROTOBUF_EXPORT RpcChannel {
 public:
  inline RpcChannel() {}
  virtual ~RpcChannel();

  // Call the given method of the remote service.  The signature of this
  // procedure looks the same as Service::CallMethod(), but the requirements
  // are less strict in one important way:  the request and response objects
  // need not be of any specific class as long as their descriptors are
  // method->input_type() and method->output_type().
  virtual void CallMethod(const MethodDescriptor* method,
                          RpcController* controller, const Message* request,
                          Message* response, Closure* done) = 0;

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
};

很显然,这是个抽象基类,需要用户自己实现派生类重写基类的CallMethod方法
在之后login和GetFriendsList两个方法基本调用方式一样,都是通过_channel调用CallMethod方法执行对应rpc调用,那么可知UserService_Stub是服务消费者(Caller)

如何发布一个本地rpc服务?

#include <iostream>
#include <string>
#include "user.pb.h"
class UserService : public fixbug::UserServiceRpc    //使用rpc服务发布端(rpc服务提供者)
{
public:
    bool Login(std::string name, std::string pwd)
    {
        std::cout<<"doing local service : Login" << std::endl;
        std::cout<< "name:" << name << "pwd :" << pwd << std::endl;
    }    

/**
 * 重写基类UserServiceRpc的虚函数 下面这些方法都是框架直接调用的
 * caller   ===> Login(LoginRequest)  ==> transmit ==>  callee
 * callee   ===> Login(LoginRequest) ===> 调用下述的Login方法
 * */
    void Login(::google::protobuf::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done)
    {
        //框架给业务上报了请求参数LoginRequest 应用获取相应数据做本地业务
        std::string name = request->name();
        std::string pwd = request->pwd();
        
        //本地业务
        bool res = Login(name, pwd);

        //把响应写入 包括错误码、错误消息、返回值
        response->set_success(0);
        fixbug::ResultCode* rc = response->mutable_result();
        rc->set_errcode(0);
        rc->set_errmsg("");

        //执行回调操作   执行响应对象数据的序列化和网络发送(由框架来完成)
        done->Run();
    }
};

继承对应的UserServiceRpc服务提供者,重写其基类方法即可。
上面只是发布过程,具体rpc调用待续。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值