gprc python调用c++远程服务_part1(简单基础和代码编写)

 

 客户端和服务端之间不是直接通信的,需要通过生成的代码和protocol buffers传输协议(可使用其他传输协议替换)进行通信。

开发步骤:

 

 

1. .proto文件----message和service

message是消息类型,定义参数,service是接口类型,定义远程服务的方法

在grpc中有四种类型的服务方法:参考

1.简单rpc,即一元消息:客户端向服务端发送一个请求,服务端响应,类似普通的函数调用 

rpc SimpleRPC(HelloRequest) returns (HelloResponse);

2.服务端流式rpc:客户端向服务端发送一个请求,服务端返回一个流。客户端可以从这个流中读取,直到服务端关闭这个流。

rpc ServerSideStreamingRPC(HelloRequest) returns (stream HelloResponse);

流式传输方式就是不将数据一次性传输完,数据被划分为小块传输,每个小块传输完后可以立即处理,减少等待时间,提高传输效率,但是可靠性可能会降低。】

3.客户端流式rpc:客户端向服务端发起流式请求,客户端可以多次向流中写入数据,服务端从流中多次读取数据直到客户端关闭流。服务端处理完所有数据后,向客户端返回普通响应。

rpc ClientSideStreamingRPC(stream HelloRequest) returns (HelloResponse);

4.双向流式rpc:客户端发起流式请求,服务端返回流式响应。两个流相互独立,互不影响。

rpc BidrectionalStreamingRPC(stream HelloRequest) returns (stream HelloResponse);

 

编写.proto代码后,运行下面的两个命令分别生成两个py文件,.cc和.h文件

python需要安装grpcio模块和grpcio-tools工具,直接用pip安装即可

python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. example.proto
protoc -I ./ --grpc_out=./ --plugin=protoc-gen-grpc=./grpc/cmake/build/grpc_cpp_plugin ./example.proto    //自动生成example.grpc.pb.cc和example.grpc.pb.h文件

 生成的代码中

namespac::grpc::service是grpc c++库的一个基类,用于定义grpc服务的接口,它是一个抽象类为派生类提供了处理grpc请求的能力。

::grpc::service中定义了一组虚函数用来处理特定服务中定义的rpc方法,这些虚函数应该在派生类中被实现以处理客户端请求并生成响应。

 

2.代码如下: 

proto:

syntax = "proto3";
package grpcdemo;
message InMatrix{  //请求参数
  repeated double row_matrix = 1;
  repeated int32 shape=2;
  int32 patch=3;
}

message OutCovMatrix{  //响应参数
  repeated double res_cov_data = 1;
}

service ScovMatrixService{   //函数
  rpc CalculateCovResult (InMatrix) returns (OutCovMatrix) {}
}

 

客户端代码:

"""The Python implementation of the GRPC drproject.Greeter client."""

from __future__ import print_function

import logging
import numpy as np
import grpc
import library.drproject_pb2 as drproject_pb2
import library.drproject_pb2_grpc as drproject_pb2_grpc

def run():
    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
    # used in circumstances in which the with statement does not fit the needs
    # of the code.
    print("Will try to greet world ...")
    row_matrix=np.array([0.1,1,0.2,2,0.3,3])
    shape=np.array([3,1,1,2])
    patch=1
    with grpc.insecure_channel('localhost:3201') as channel:
        stub = drproject_pb2_grpc.ScovMatrixServiceStub(channel)
        response = stub.CalculateCovResult(drproject_pb2.InMatrix(row_matrix=row_matrix,shape=shape,patch=patch))
    print("asdas")
    res_cov=np.zeros(shape[0]*shape[3]*shape[3])
    i=0
    for m in response.res_cov_data:
        res_cov[i]=m
        print(res_cov[i])
        i+=1

if __name__ == '__main__':
    logging.basicConfig()
    run()

  

服务端代码:

#include<iostream>
#include<memory>
#include<vector>

#include <grpc/grpc.h>  
#include <grpcpp/grpcpp.h>
#include <grpcpp/server.h>  
#include <grpcpp/server_builder.h>  
#include <grpcpp/server_context.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/health_check_service_interface.h>

#include"drproject.grpc.pb.h"
#include"NumCpp.hpp"     //项目需要使用到了numcpp和boost库
#include"boost/filesystem.hpp"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::Status;
using grpc::ServerContext;

using grpcdemo::ScovMatrixService;
using grpcdemo::InMatrix;
using grpcdemo::OutCovMatrix;

class Implement final: public ScovMatrixService::Service{
 //the class Implement inherit from grpc::Service    why?
public:
   Status CalculateCovResult(ServerContext* context, const InMatrix* request, OutCovMatrix* response) override
    {
      //解析数据
int num=request->shape(0); int Hei=request->shape(1); int Wid=request->shape(2); int Band=request->shape(3); int S=Hei*Wid; const int32_t patch=request->patch(); //使用一维数组进行传递 std::vector<double>vec(num*Hei*Wid*Band); for(int i=0;i<num*Hei*Wid*Band;i++){ vec[i]=request->row_matrix(i); } auto X_tr1 = nc::NdArray<double>(vec,true); for(int i=0;i<num*Hei*Wid*Band;i++){ std::cout<<X_tr1[i]<<" "; response->add_res_cov_data(X_tr1[i]/2); //返回矩阵数据 } std::cout<<"compute ok"<<std::endl; return Status::OK; } }; void RunServer(){ Implement covservice; ServerBuilder builder; builder.AddListeningPort("localhost:3201",grpc::InsecureServerCredentials()); builder.RegisterService(&covservice); std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on 3201" << std::endl; server->Wait(); } int main(){ RunServer(); return 0; }

 

如果有帮助求个小小的赞^_^,有问题欢迎不吝赐教!

 

下面是学习过程中遇到的问题及部分解决方法,可以不看

3.使用简单rpc编写客户端python代码和服务端c++代码

 简单编写后遇到以下问题:【更新:解决方法是使用cmakelists.txt文件编译c++程序,可以参照grpc源代码中给出的example】

 

简单编写客户端代码后,思考一个问题,由于客户端处理的是多维数据,传递给服务端的矩阵形状为[L, P, P, B],以及一个数组np.array([L, P, P, B]),c++服务端返回给客户端的矩阵形状是[B, B]。python传递的是numpy数组,c++端怎样接收。【更新:答案:参考上述代码,传递和接收之前会经过protobuf的序列化和反序列化,这些已经帮我们实现好了,暂时不需要考虑,按顺序读取内容即可】

 在生成的pb.h文件中,可以看到读取和设置参数row_matrix的方法如下,设置是set_row_matrix,读取是按下标读取row_matrix(index)。

 

对于服务端代码,在.grpc.pb.h中找到自动生成的服务类的虚函数,新建一个cpp文件,其中继承该类并实现其中的虚函数。

 

遇到的问题记录:

在简单编写服务端代码后,进行编译和链接,编译无问题(gcc -c server.cpp 执行后生成了server.o目标文件),链接阶段出现了很多undefined reference to...的问题。可能是没有找到需要链接的库,关于这一方面我其实现在不是特别清楚为什么它找不到需要链接的库。

 

grpc在编译和安装后会生成哪些文件,分别位于什么位置?

会生成grpc插件文件:这些文件用于根据.proto文件完成客户端和服务端代码的生成,例如grpc_cpp_plugin等

编译生成的库文件:编译和安装过程将生成静态库文件和动态库文件,用于在应用程序中链接和使用grpc,通常生成的库文件会被安装到系统库目录或指定目录中。我系统上安装到了/usr/local/include/grpc下面。

通过在网上找相关问题,可能是RTTI和no-RTTI同时存在的问题,对于这个可以问题可以看这篇博客,另外,这篇是个人学习记录

posted @ 2023-06-08 23:23  阳光中的影子  阅读(239)  评论(0编辑  收藏  举报