Protoc与GRPC的使用

Protobuf与GRPC

安装

https://github.com/protocolbuffers/protobuf/releases

已经有构建好的运行文件,可以下载压缩包在bin/目录下找到,如果想自己构建请访问https://github.com/protocolbuffers/protobuf/blob/main/src/README.md

安装完成后运行protoc --version查看是否成功。

protoc作用是将.proto文件转换,至于转换成什么语言需要我们指定参数,比如Go语言需要指定–go_out ,指定完参数我们还不能实现proto->go的转换,因为我们还缺少protoc-gen-go运行文件

旧版本:运行go install github.com/golang/protobuf/protoc-gen-go对protoc-gen-go进行安装,当然也可以下载源码手动构建(go get -u 就是这么做的)

新版本:go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

go install google.golang.org/protobuf/cmd/protoc-gen-go

注意,protobuf有两个重要的版本区别,旧版本github.com/golang/protobuf/protoc-gen-go 它带有protoc-gen-go,它生成protobuf消息的序列化和 grpc代码(使用–go_out=plugins=grpc时)

新版本 google.golang.org/protobuf/ 不再支持生成 gRPC 服务定义,如果想要生成grpc代码需要使用新插件protoc-gen-go-grpc。

plugins参数 是旧版本,新版本已弃用。新版本方法是 --go-grpc_out=。这里我们使用新版本。

为什么要安装protoc-gen-go那?因为protoc没有内置go生成器,所以在生成时会去系统bin/中查询protoc-gen-go,然后使用protoc-gen-go生成go文件。

语法

protobuf语法

使用

注意 --I可以指定.proto依赖包,如果在.proto文件中使用import的话。

protoc --go_out=:./ *.proto
protoc --go-grpc_out=. *.proto

该指令意思是,生成go代码。

第二行生成与grpc相关操作的代码

注意:如果预见helloworld.proto:23:1: Import “google/api/annotations.proto” was not found or had errors.这种错误,请下载google/api包

url-> grpc

protoc采用插件式所以,有很多插件可以方便我们的工作,下面讲解两个插件的使用

gateway

gateway的作用是将restful与grpc请求建立映射关系,让用户可以通过restful调用grpc

go get -u github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway

protoc -I . --grpc-gateway_out . --grpc-gateway_opt logtostderr=true helloworld.proto

使用-i是因为 .proto文件中使用了import “google/api/annotations.proto”;

-I的作用是指定要搜索的目录,并且可以指定多个。

syntax = "proto3";

//文件输出路径一定要有/否则报错
option go_package = "./helloworld";

package helloworld;

//引入依赖包
import "google/api/annotations.proto";

// 接口
service Greeter {
  // 方法
  rpc SayHello (HelloRequest) returns (HelloReply) {
    //配置gateway
    option (google.api.http) = {
      get:"/v1/examples/sayhello"
    };
  }
}
// 类
message HelloRequest {
  string name = 1;
}

// 类
message HelloReply {
  string message = 1;
}
swagger

swagger这个没什么好说的,懂的都懂

go get -u github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2

protoc   --openapiv2_out . --openapiv2_opt logtostderr=true *.proto 

如果go get 安装不行就需要手动源码安装https://github.com/grpc-ecosystem/grpc-gateway/

会自动生成一个swagger.json文件。

注意:在运行时可能报找不到*.protoc文件一般是annotations.proto等,请自行下载文件放入目录中。

有啥用?

那么对于生成的文件我们应该怎么用,他们每个文件又有什么含义那?

首先*.pb.go 为纯go语言生成类与方法(这里有版本区别,新版本意思不变,旧版本的话如果配置了grpc插件会将grpc相关的操作也会在这个文件生成)。

那么对于新版本来说 类文件与grpc操作分开存放,*_grpc.pb.go为grpc操作的文件。

我们在使用的时候,如果某些功能不建议使用grpc的情况下该怎么办那,这时候gateway就出厂了,gateway作用是使用ServeMux将grpc操作封装成restful接口。

Grpc

上面我们讲解了protoc如何生成文件,以及每个文件有什么用,接下来我们将讲解GRPC使用方法。

在https://github.com/grpc/grpc-go.git examples目录下有grpc的测试DEMO

接下来让我们使用官方实例Helloworld进行代码讲解

客户端

package main
import (
	"context"
	"flag"
	"log"
	"time"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
	defaultName = "world"
)
var (
	addr = flag.String("addr", "localhost:50051", "the address to connect to")
	name = flag.String("name", defaultName, "Name to greet")
)
func main() {
	flag.Parse()
	// 创建grpc连接,第一参数为服务器地址,第二个参数是配置
	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
  // 封装成GreeterClient,目的是达到调用方法就能发送请求的目的。(嗯本质就是客户端服务器呗RPC也是)。
	c := pb.NewGreeterClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    // 调用方法,请求,原理是使用上面创建的conn发送请求。这里需要注意传入的类时我们通过proto生成的类,
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
}

客户端配置

 conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
// 第二个参数为配置参数
//我们不需要传入整个Option类
//GRPC给我们封装成了方法形式代用配置,
//具体方法可以根据下面的配置类转换(将首字母转换成大写,智能提示应该就可以提示出来)
type dialOptions struct {
    // 拦截器,在invoke方法中调用
    /*
    if cc.dopts.unaryInt != nil {
		return cc.dopts.unaryInt(ctx, method, args, reply, cc, invoke, opts...)
	}
	return invoke(ctx, method, args, reply, cc, opts...)
    */
	unaryInt  UnaryClientInterceptor
    // 流拦截器
	streamInt StreamClientInterceptor
    // 拦截链
	chainUnaryInts  []UnaryClientInterceptor
    // 拦截链
	chainStreamInts []StreamClientInterceptor
    // 定义GRPC失败策略
	bs                          internalbackoff.Strategy
    // 拨号阻塞
	block                       bool
    // 超时时间
	timeout                     time.Duration
    // 连接方式 默认是ServerName
	authority                   string
    //  transport.ConnectOptions
	copts                       transport.ConnectOptions
    // 前后置处理器
	callOptions                 []CallOption
    // channelz数据库标识
	channelzParentID            *channelz.Identifier
    //
	disableServiceConfig        bool
    //
	disableRetry                bool
    //
	disableHealthCheck          bool
    //
	healthCheckFunc             internal.HealthChecker
    // 
	minConnectTimeout           func() time.Duration
    //
	resolvers                   []resolver.Builder
}

服务端

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

var (
	port = flag.Int("port", 50051, "The server port")
)

// 我们需要实现接口类,但是这里并没有,而是继承了UnimplementedGreeterServer类,目的是可以不实现接口的所有方法,而另一个目的,在生成时UnimplementedGreeterServer类实现了SayHello方法,其功能就是返回没有实现当前方法信息,提醒我们需要去主动重构。
type server struct {
	pb.UnimplementedGreeterServer
}

// 实现方法,返回值使用生成的类
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	flag.Parse()
    // 创建监听事件
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
    // 创建grpc服务器
	s := grpc.NewServer()
    // 注册grpc服务器,将请求服务名与方法绑定
    // 这里是 服务名helloworld.Greeter,方法 SayHello
    // 客户端在请求的时候就是根据服务名进行请求的。
	pb.RegisterGreeterServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
    // 启动监听事件
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

在使用过程中,proto插件已经将我们需要的grpc操作生成完成,我们只需要对其进行调用即可。

服务端配置

下面我们讲一下创建GRPC时可以进行的配置

// NewServer(opt ...ServerOption)
s := grpc.NewServer()
//但是我们不需要传入整个ServerOption类
//GRPC给我们封装成了方法形式代用配置,例如   NewServer(grpc.WriteBufferSize(1))
//具体方法可以根据下面的配置类转换(将首字母转换成大写,智能提示应该就可以提示出来)
type serverOptions struct {
   // 定义协议支持,比如TLS、SSL
   creds                 credentials.TransportCredentials
   //包含了Codec and encoding.Codec
   codec                 baseCodec
   /*拦截器,在即将调用SayHello方法时调用,
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
   	return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
	}
	return interceptor(ctx, in, info, handler)*/
   unaryInt              UnaryServerInterceptor
   //拦截流器
   streamInt             StreamServerInterceptor
   //拦截链,GRPC内部会将其处理成链
   chainUnaryInts        []UnaryServerInterceptor
   //拦截链,GRPC内部会将其处理成链
   chainStreamInts       []StreamServerInterceptor
   //
   inTapHandle           tap.ServerInHandle
   //处理连接接口
   statsHandler          stats.Handler
   //限制最大并发流  通过MaxConcurrentStreams(n uint32)设置
   maxConcurrentStreams  uint32
   // 默认1024 * 1024 * 4  最大接收消息大小
   maxReceiveMessageSize int
   // 默认math.MaxInt32 最大发送消息大小
   maxSendMessageSize    int
   // 设置一个404处理
   unknownStreamDesc     *StreamDesc
   //服务器设置 keepalive 和 max-age 参数
   keepaliveParams       keepalive.ServerParameters
   //keepalive 强制策略
   keepalivePolicy       keepalive.EnforcementPolicy
   // 流设置窗口大小 窗口大小的下限是 64K,任何小于该值的值都将被忽略。
   initialWindowSize     int32
   //连接窗口大小 窗口大小的下限是 64K,任何小于该值的值都将被忽略。
   initialConnWindowSize int32
   //默认32 * 1024 写缓存
   writeBufferSize       int
   //默认32 * 1024 读缓存
   readBufferSize        int
   // 连接超时时间 默认120 * time.Second 
   connectionTimeout     time.Duration
   maxHeaderListSize     *uint32
   headerTableSize       *uint32
   // 设置处理传入流的并发数 设置0则每个都创建一个并发
   numServerWorkers      uint32
}

Grpc gateway

我们生成了gateway那么应该怎么使用它那?

ctx := context.Background()
mux := http.NewServeMux()
muxgw := runtime.NewServeMux()

// http到grpc映射,添加到muxgw中
helloworld.RegisterGreeterHandlerServer(ctx, muxgw, &server{})

mux.Handle("/", muxgw)
mux.HandleFunc("/test", func(writer http.ResponseWriter, request *http.Request) {
   writer.Write([]byte("fewafa"))
},
)
fmt.Println("开始监听")
http.ListenAndServe("localhost:8090", mux)

我们请求http://localhost:8090/v1/examples/sayhello查看是否返回正确的信息

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在VxWorks中使用gRPC,你可以按照以下步骤进行: 1. 准备VxWorks环境:确保你已经配置好VxWorks开发环境,包括安装和设置好VxWorks SDK。 2. 下载gRPC和protobuf:从gRPC的GitHub仓库中下载gRPC和protobuf的源代码,或者使用包管理工具(如pip)进行安装。 3. 定义gRPC接口:使用Protocol Buffers语言(proto)定义远程过程接口和消息结构。创建一个.proto文件,描述你的服务和消息结构。 4. 生成代码:使用protoc工具来生成VxWorks所需的代码。运行以下命令: ``` protoc --grpc_out=. --plugin=protoc-gen-grpc=<path_to_grpc_cpp_plugin> --cpp_out=. your_service.proto ``` 将 `<path_to_grpc_cpp_plugin>` 替换为你的机器上实际的 gRPC C++ 插件路径。 5. 创建VxWorks应用程序:在VxWorks中创建一个新的应用程序或打开现有的应用程序。 6. 添加gRPC和protobuf依赖:将生成的代码和gRPC以及protobuf的库文件添加到你的VxWorks应用程序中。确保正确设置包含路径和链接选项。 7. 实现gRPC服务端:在VxWorks应用程序中实现你的gRPC服务端逻辑。创建一个类继承自你生成的gRPC服务接口,并实现相应的远程过程调用方法。 8. 实现gRPC客户端:在VxWorks应用程序中实现你的gRPC客户端逻辑。创建一个gRPC客户端对象,通过调用服务端的远程过程来进行通信。 9. 构建和部署:使用VxWorks SDK将你的应用程序构建为可执行文件,并将其部署到VxWorks系统中。 10. 启动服务端和客户端:在VxWorks系统中启动服务端和客户端应用程序。服务端应处于监听状态,等待来自客户端的gRPC调用请求。 11. 远程过程调用:通过客户端应用程序调用服务端的远程过程。gRPC将负责将调用请求传递给服务端,并将响应返回给客户端。 需要注意的是,以上步骤提供了一个基本的框架来在VxWorks中使用gRPC。具体的实现细节和配置可能因项目需求和VxWorks版本而有所不同。你可能还需要参考VxWorks的官方文档和相关资料,以了解更多关于在VxWorks中使用gRPC的详细步骤和指导。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值