简单使用gRPC
gRPC是google开发的一个远程过程调用框架,搭配protobuf使用来实现从客户端调用服务器端对应程序的方法。
protobuf
protobuf可以理解为一种传输协议或者传输格式,相比json等网络传输形式,具有更好的效率。gRPC使用这种协议来实现高效的网络传输。
proto
只需要编写proto文件,再使用gRPC提供的工具,就可以直接生成多种语言的客户端和服务端,以及对应的protobuf协议,因此还可以实现跨语言的程序调用。简单的proto文件格式如下:
1 | # service.proto |
syntax关键字指定了protobuf的版本,默认版本是proto2,一般指定使用proto3。
package关键字将会生成一个命名空间,用于隔离代码,下面生成的服务和请求格式都会放到message这个命名空间下。
service关键字指明了我们要生成的客户端和服务端的名称,然后内部通过rpc关键字表示将会调用到的函数,这里我们创建的客户端和服务端的RPC服务就叫HelloWorld,里面有一个会被远程调用的函数叫sayHello,入参是一个Request类型,出参是Response类型,这两个类型在下面通过message关键字来定义。
生成客户端和服务端
当客户端HelloWorld调用sayHello时,会通过网络将Request传递到同名的服务端HelloWorld中,然后HelloWorld调用同名的sayHello函数,将执行结果返回。
服务端
在生成好proto文件后,我们要在自己的代码中实例化我们定义的gRPC服务。
查看生成好的源文件能够看到,在对应的类内部会有一个HelloWorld::Service的类,我们需要继承这个类,然后来实现对应的逻辑。
1 | // 服务的具体实现 |
然后编写一个启动服务实现类的函数,主函数中调用这个函数就可以启动服务了。
1 | void RunServer() { |
首先是设置监听地址和端口,然后通过gRPC中提供的ServerBuilder构建类来构建出一个服务,最后使用服务的Wait函数,服务将进入阻塞等待接收消息。
客户端
同样,我们也可以定义一个自己的客户端类,并在这个类中包含gRPC客户端对应的“存根”,gRPC客户端主要就是通过这个存根来和服务器端进行通信的。
1 | class HelloWorldClient { |
关键部分在于HelloWorld::Stub,Channel和ClientContext,HelloWorld::Stub就是我们说的存根,这个是在生成的gRPC源文件中自动生成的,这个类的实现需要一个通道Channel,Channel中可以设置要通信的服务端的地址和端口号。
1 | std::shared_ptr<Channel> channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); |
在远程调用sayHello时,还需要传入一个叫做客户端上下文的东西,也就是ClientContext,还有表示接口调用状态的Status,都可以在grcpp中找到,引入对应的头文件即可。