一个grpcServer实现多个proto文件

本文介绍了如何在一个GRPC Server中同时处理来自不同proto文件的服务接口,包括api决策和api服务,展示了如何创建一个结构体并实现多个接口以注册到服务器,以及如何通过pb.go文件中的注册方法进行注册过程。

一个GRPCServer实现多个proto文件

  1. 多个proto文件定义在同一个package包中
  2. 每个proto文件中的service不相同(多个接口)
  3. 注册GRPCServer的结构体需要实现多个proto文件中定义的接口的方法
  4. 注册GRPCServer时需要调用每个pb.go文件中的RegisterXXXXServer方法

举例

  • 第一个proto文件

    syntax = "proto3";
    
    package api;
    
    service Decision {
      rpc Decision(DecisionReq) returns (DecisionRes){}
    }
    
    message DecisionReq {
      string Headers = 1;
      int64 MemberId = 2;
    }
    
    message Error {
      string Error = 1;
      int64  Code = 2;
    }
    
    message DecisionRes {
      int64 Code = 1;
      Error Result = 2;
      int64  ResultType = 3;
      string RequestId = 4;
      int64 Timestamp = 5;
    }
    
  • 第二个proto文件

    syntax = "proto3";
    
    package api;
    
    service Api {
      // Sends a greeting
      rpc HelloWorld(HelloReq) returns (HelloRes) {}
    }
    
    message HelloReq {
      string Name = 1;
    }
    
    message HelloRes {
      string Res = 1;
    }
    
  • 注册server

    package handler
    
    import (
    	pb "api_server/handler/proto"
    	"google.golang.org/grpc"
    	"log"
    	"net"
    )
    
    var gServer = grpc.NewServer()
    
    type Api struct{} // 实现多个proto文件中定义的方法
    
    func Start(addr string) {
    	conn, err := net.Listen("tcp", addr)
    	if err != nil {
    		log.Fatalf("net listen err: %v", err)
    	}
    	pb.RegisterApiServer(gServer, &Api{}) // 多次注册
    	pb.RegisterDecisionServer(gServer, &Api{}) // 多次注册
    	gErr := gServer.Serve(conn)
    	if gErr != nil {
    		log.Fatalf("grpc server err:%v", err)
    	}
    }
    
    func Stop() {
    	gServer.GracefulStop()
    	log.Println("grpc server stop")
    }
    
### 使用 Protocol Buffers 生成 C++ 代码并搭建 gRPC 服务器和客户端 #### 定义 `.proto` 文件 首先,需要定义一个 `.proto` 文件来描述数据结构和服务接口。例如,假设有一个名为 `message.proto` 的文件,其内容如下: ```protobuf syntax = "proto3"; package example; // 定义请求和响应消息格式 message Com { message Compo { uint32 id = 1; uint32 com = 2; } repeated Compo comp = 1; } // 定义服务接口 service Greeter { rpc SayHello (Com) returns (Com); } ``` 在这个文件中,`repeated Compo comp = 1;` 表示该字段是一个重复字段,类似于 C++ 中的 `std::vector` 容器[^1]。 #### 生成 C++ 和 gRPC 代码 使用 `protoc` 工具生成 C++ 代码和 gRPC 代码: ```bash protoc -I="." --cpp_out="." message.proto protoc -I="." --grpc_out="." --plugin=protoc-gen-grpc=/usr/bin/grpc_cpp_plugin message.proto ``` 这将生成多个文件: - `message.pb.h` 和 `message.pb.cc`:包含由 `.proto` 文件定义的消息类型的序列化代码。 - `message.grpc.pb.h` 和 `message.grpc.pb.cc`:包含 gRPC 服务和客户端的存根代码[^3]。 #### 实现 gRPC 服务端 在服务端,需要实现定义的服务接口,并启动 gRPC 服务器。以下是一个简单的实现示例: ```cpp #include <iostream> #include <memory> #include <grpcpp/grpcpp.h> #include "message.grpc.pb.h" using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using example::Com; using example::Greeter; class GreeterServiceImpl final : public Greeter::Service { Status SayHello(ServerContext* context, const Com* request, Com* response) override { for (const auto& item : request->comp()) { std::cout << "Received ID: " << item.id() << ", COM: " << item.com() << std::endl; Com::Compo* new_item = response->add_comp(); new_item->set_id(item.id()); new_item->set_com(item.com()); } return Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; server->Wait(); } int main() { RunServer(); return 0; } ``` #### 实现 gRPC 客户端 在客户端,需要创建一个通道连接到服务端,并调用远程方法。以下是一个简单的实现示例: ```cpp #include <iostream> #include <grpcpp/grpcpp.h> #include "message.grpc.pb.h" using grpc::Channel; using grpc::ClientContext; using grpc::Status; using example::Com; using example::Greeter; class GreeterClient { public: GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} void SendData() { ClientContext context; Com request; Com::Compo* item1 = request.add_comp(); item1->set_id(1); item1->set_com(2); Com response; Status status = stub_->SayHello(&context, request, &response); if (status.ok()) { for (const auto& item : response.comp()) { std::cout << "Response ID: " << item.id() << ", COM: " << item.com() << std::endl; } } else { std::cout << status.error_code() << ": " << status.error_message() << std::endl; } } private: std::unique_ptr<Greeter::Stub> stub_; }; int main() { GreeterClient client(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials())); client.SendData(); return 0; } ``` #### 编译和运行 确保安装了 gRPCProtocol Buffers 库,并且正确配置了编译环境。编译命令可能如下所示: ```bash g++ -std=c++11 -o server server.cpp message.pb.cc message.grpc.pb.cc -lgrpc++ -lprotobuf -pthread g++ -std=c++11 -o client client.cpp message.pb.cc message.grpc.pb.cc -lgrpc++ -lprotobuf -pthread ``` 运行服务端和客户端: ```bash ./server ./client ``` 服务端将监听端口 `50051`,客户端将发送请求并接收响应[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值