使用gRPC进行跨语言服务通信

​     gRPC是基于HTTP/2的通信协议框架(Dubbo是基于tcp的),同时采用了Protocol Buffers(Protobuf) 作为序列化框架。protobuf也是google开源的一款序列化产品。与开发语言无关,和平台无关,具有良好的可扩展性。Protobuf和所有的序列化框架一样,都可以用于数据存储、通讯协议。众所周知,使用一些老牌的rpc框架如Dubbo等很难进行不同语言服务之间的通信(当然Dubbo目前也已经引入了protobuf进行跨语言通信),gRPC作为一款google开源的rpc框架,不仅支持跨语言、跨平台并且性能极高,在云时代,gPRC无疑是一个宠儿。今天就来聊一下gRPC的使用。

示例采用Java做客户端,C++做服务端进行通信,示意图如下:

image-20210913131519199

1.编写proto文件

​     使用gRPC要先编写proto文件(文件名:greet.proto),关于proto文件的介绍可以看下官网

syntax = "proto3";
package greet;
//定义一个service服务,这里在C++和Java中相当于一个类
service Greeting {
  // 定义一个函数,这里在C++和Java中相当于一个方法
  rpc sayHello (GreetRequest) returns (GreetResponse) {}
}
//定义请求的消息实体
message GreetRequest {
  //在C++和Java中这个类型相当于int
  int32 age = 1;
  string name = 2;
}
//定义返回的消息实体
message GreetResponse {
  string result = 1;
}

2.开发Java客户端

使用gradle构建Java项目,build.gradle如下:

plugins {
    id 'java-library'
    id 'com.google.protobuf' version '0.8.17'
}

group 'com.tanky'
version '1.0.0'

repositories {
    mavenLocal()
    mavenCentral()
}
dependencies {
    implementation 'io.grpc:grpc-netty-shaded:1.40.1'
    implementation 'io.grpc:grpc-protobuf:1.40.1'
    implementation 'io.grpc:grpc-stub:1.40.1'
}
protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.17.3"
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.40.1'
        }
    }
    generateProtoTasks.generatedFilesBaseDir="src"
    generateProtoTasks {
        all()*.plugins {
            grpc {
                setOutputSubDir'java'
            }
        }
    }
}

在gradle中引入protobuf的插件,该插件引入以后在执行的时候会下载对应的protobuf的编译器以及将proto文件生成Java代码的插件。将编写好的greet.proto文件放在src/main/poto/下,在插件生成Java代码的时候会自动去改目录下寻找。

image-20210913131916466

执行结束以后会在src/main/java/下生成greet目录,目录中会有两个类分别是Greet和GreetingGrpc,其中Greet就是我们在.proto中定义的message,GreetingRrpc就是我们定义的service。示意图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4rHpAIWr-1631517820117)(https://i.loli.net/2021/09/13/NwjyIRbSphgaKQd.png)]

具体的代码结构在这里就不做过多介绍,我们直接看如何编写Client的代码:

package com.tanky.grpc.client;

import greet.Greet;
import greet.GreetingGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

/**
 * @author tanky
 * Grpc客户端
 */
public class GreetClient {

    public static void main(String[] args) {
        
        //构建channel通道,服务在本机的5000端口启动,这里可以改成自己的ip和端口
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 5000).usePlaintext().build();
        //构建代理对象stub
        GreetingGrpc.GreetingBlockingStub greetingBlockingStub = GreetingGrpc.newBlockingStub(managedChannel);
        //构建请求实体对象
        Greet.GreetRequest greetRequest = Greet.GreetRequest.newBuilder().setAge(18).setName("tanky").build();
        //进行rpc通信,获得返回的实体对象
        Greet.GreetResponse greetResponse = greetingBlockingStub.sayHello(greetRequest);

        System.out.println(greetResponse.getResult());
    }

}

至此,Java Client就完成了。

3.开发C++服务端

​​     C++的服务端开发相对来说复杂一点,我也是好长时间没用C++了又有些生疏,遇到了很多坑。C++不像Java那般可以用插件直接将proto文件生成Java代码,而它必须使用protobuf以及gRPC的编译器,自己将proto文件编译称C++文件。关于protobuf和gRPC的编译器可以在官网下载。编译器可以直接下载可执行文件,也可以下载源码自己进行编译,因为我的电脑是Mac的M1,没有在官网上找到合适的可执行文件,所以自己下载源码进行了编译,并且gRPC官网对于C++的quick start也推荐使用编译源码的方式,具体的使用过程可以看官网Quick start,后续我也将会整理一份放在博客上。

在greet.proto所在目录执行两条shell命令:

#生成 greet.pb.cc、greet.pb.h(请求实体相关类的生成)
protoc --cpp_out=./ greet.proto;
#生成greet.grpc.pb.cc、greet.grpc.pb.h(请求的函数相关的类)
protoc --grpc_out=./ --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` greet.proto;

执行完成后在当前目录会生成greet.pb.cc、greet.pb.h、greet.grpc.pb.cc、greet.grpc.pb.h四个文件,将这两个文件拷贝到自己的C++项目中,我的C++项目是使用Clion编写的,具体如下:

image-20210913150317549

放进去以后C++不像Java般智能,Java可以直接在build.gradle中引入所需要的gRPC的jar包,而C++不行,他所依赖的库必须在本地,并且需要手工引入。C++所依赖的gRPC的库和protobuf的库,都在我的/usr/local/下,这些库在编译gRPC和protobuf的编译器的时候已经生成在/usr/local/下了,此时我们只需要在CMakeLists.txt中定义就可以了。

CMakeLists.txt:

cmake_minimum_required(VERSION 3.19)
#项目名
project(cpuls)
#定义C++标准
set(CMAKE_CXX_STANDARD 11)
#-I 添加头文件目录INCLUDE_DIRECTORIES
include_directories(/usr/local/protobuf/include)
#-L 添加需要链接的库文件目录LINK_DIRECTORIES
link_directories(/usr/local/protobuf/lib)
#-I
include_directories(/usr/local/include)
#-L
link_directories(/usr/local/lib)
add_executable(cpuls Server.cpp greet.pb.cc greet.grpc.pb.cc)
#显示指定链接动态库
target_link_libraries(cpuls protobuf grpc gpr grpc++)

然后编写C++服务端程序代码:

#include <string>
#include <grpcpp/grpcpp.h>
#include "greet.grpc.pb.h"

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

class MathServiceImplementation final : public Greeting::Service {
    Status sayHello(ServerContext *context, const GreetRequest *request, GreetResponse *reply) override {
        int age = request->age();
        std::string name = request->name();
        std::cout << "年龄为" << age << "姓名为" << name << std::endl;
        reply->set_result("hello world!!!");
        return Status::OK;
    }
};

int main(int argc, char **argv) {
    std::string address("localhost:5000");
    MathServiceImplementation serviceImplementation;
    ServerBuilder builder;
    builder.AddListeningPort(address, grpc::InsecureServerCredentials());
    builder.RegisterService(&serviceImplementation);
    std::unique_ptr<Server> server(builder.BuildAndStart());
    std::cout << "Server listening on port: " << address << std::endl;
    server->Wait();
    return 0;
}

至此,C++服务端代码编写完成。

4.最终效果

启动C++服务端程序终端显示如下:

image-20210913151858037

启动Java客户端程序如下:

image-20210913151953398

服务端返回了hello world!!!。此时再看服务端终端的输出:

image-20210913152105234

服务端输出了姓名和年龄,至此gRPC的跨语言rpc通信演示例子最终效果演示完成。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#与gRPC通信可以通过使用gRPC框架来实现。gRPC是一种高性能、开源的、通用的远程过程调用(RPC)框架,它可以在多种编程语言使用,并支持平台、语言通信。 下面是在C#中使用gRPC进行通信的一般步骤: 1. 定义gRPC服务和消息:首先,在.proto文件中定义gRPC服务和消息。这些文件描述了服务的方法、参数和返回类型。 2. 生成代码:使用gRPC的工具生成C#的客户端和服务端代码。 3. 实现服务端:在服务端,你需要实现.proto文件中定义的服务接口。这些接口将作为服务实现的基础。 4. 实现客户端:在客户端,你可以使用生成的客户端代码来调用服务器上定义的方法。 5. 构建和运行:构建和运行服务端和客户端代码。 下面是一个简单的示例,展示了如何在C#中使用gRPC进行通信: 1. 创建.proto文件,比如hello.proto,包含以下内容: ``` syntax = "proto3"; service HelloService { rpc SayHello (HelloRequest) returns (HelloResponse) {} } message HelloRequest { string name = 1; } message HelloResponse { string message = 1; } ``` 2. 使用gRPC的工具生成C#代码。在命令行中执行以下命令: ``` protoc -I .\protos --csharp_out .\generated .\protos\hello.proto ``` 这将在generated文件夹中生成C#代码。 3. 在服务端中实现接口。在你的服务实现类中,实现HelloService中的方法,比如: ```csharp public class HelloServiceImpl : HelloService.HelloServiceBase { public override Task<HelloResponse> SayHello(HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloResponse { Message = "Hello, " + request.Name }); } } ``` 4. 在客户端中调用服务。创建一个gRPC的客户端,并调用服务器上的方法。 ```csharp var channel = new Channel("localhost", 50051, ChannelCredentials.Insecure); var client = new HelloService.HelloServiceClient(channel); var request = new HelloRequest { Name = "John" }; var response = client.SayHello(request); Console.WriteLine(response.Message); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值