内容简介:工欲善其事必先利其器,在构建Go微服务前准备好开发环境可以提供工作效率和工作的舒心度。在本文中定义一个产品服务ProductService,服务提供两个简单的基本功能一个方法不需要入参或没有返回值时,在gRPC中使用空的message代替,参考
开发环境准备
工欲善其事必先利其器,在构建 Go 微服务前准备好开发环境可以提供工作效率和工作的舒心度。
-
Go
gRPC要求Go语言的版本不低于1.6,建议使用最新稳定版本。如果没有安装Go或Go的版本低于1.6,参考 Go安装指南
$ go version
-
安装gRPC
可以使用如下命令安装gRCP:
$ go get -u google.golang.org/grpc
如果网络质量不佳,可以直接去GitHub 下载 gRPC源码,将源码拷贝到 $GOPATH 路径下。
-
安装 Protocol Buffers v3
安装protoc编译器的目的是生成服务代码,从 https://github.com/google/protobuf/releases 下载已预编译好的二进制文件是安装protoc最简单的方法。
1.1 解压文件
1.2 将二进制文件所在的目录添加到环境变量 PATH 中。
安装Go版本的protoc插件
$ go get -u github.com/golang/protobuf/protoc-gen-go
默认编译插件protoc-gen-to安装在 $GOPATH/bin 目录下,该目录需要添加到环境变量 PATH 中。
定义服务
在本文中定义一个产品服务ProductService,服务提供两个简单的基本功能
- 添加产品
- 删除产品
- 根据产品Id查询产品详情
-
查询所有产品详情
ProductService.poto文件的具体内容如下:
// protocol buffer 语法版本 syntax = "proto3"; // 产品服务定义 service ProductService { // 添加产品 rpc AddProduct (AddProductRequest) returns (AddProductResponse) { } // 删除产品 rpc DeleteProduct (DeleteProductRequest) returns (EmptyResponse) { } // 根据产品Id查询产品详情 rpc QueryProductInfo (QueryProductRequest) returns (ProductInfoResponse) { } // 查询所有产品详情 rpc QueryProductsInfo (EmptyRequest) returns (ProductsInfoResponse) { } } // 请求/响应结构体定义 // 添加产品message message AddProductRequest { enum Classfication { FRUIT = 0; MEAT = 1; STAPLE = 2; TOILETRIES = 3; DRESS = 4; } string productName = 1; Classfication classification = 2; string manufacturerId = 3; double weight = 4; int64 productionDate = 5; } // 添加产品,服务端响应message message AddProductResponse { string productId = 1; string message = 2; } // 删除产品message message DeleteProductRequest { string productId = 1; } message QueryProductRequest { string productId = 1; } // 单产品详情message message ProductInfoResponse { string productName = 1; string productId = 2; string manufacturerId = 3; double weight = 4; int64 productionDate = 5; int64 importDate = 6; } message ProductsInfoResponse { repeated ProductInfoResponse infos = 1; } message EmptyRequest { } message EmptyResponse { }
一个方法不需要入参或没有返回值时,在gRPC中使用空的message代替,参考 stackoverflow
生成客户端和服务端代码
服务定义文件ProductService.poto在工程中的路径为:src/grpc/servicedef/product/ProductService.poto,进入servicedef目录,执行以下命令生成Go版本的客户端和服务端代码:
$ protoc -I product/ ProductService.proto --go_out=plugins=grpc:product
命令执行完成后,会在product目录下生成一个名为ProductService.pb.go的文件,文件的内容为Go版本的客户端和服务端代码。
服务端实现
服务端需要完成两项工作才能对外提供RPC服务:
- 实现ProductServiceServer接口,ProductServiceServer接口是protoc编译器自动生成。在Go某个对象实现一个接口,只需要实现该接口的所有方法。
-
启动gRPC Server用来处理客户端请求。
服务端具体实现代码
package main import ( "log" "net" "time" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/reflection" pb "grpc/servicedef/product" "math/rand" "strconv" ) const ( port = ":5230" ) var dataBase = make(map[string]*Product, 10) type Product struct { ProductName string ProductId string ManufacturerId string Weight float64 ProductionDate int64 ImportDate int64 } type server struct{} func (s *server) AddProduct(ctx context.Context, request *pb.AddProductRequest) (*pb.AddProductResponse, error) { log.Printf("get request from client to add product,request is %s", request) productId := strconv.FormatInt(rand.Int63(), 10) product :=new (Product) product.ProductName = request.ProductName product.ProductId = productId product.ManufacturerId = request.ManufacturerId product.Weight = request.Weight product.ProductionDate = request.ProductionDate product.ImportDate = time.Now().UnixNano() dataBase[productId] = product return &pb.AddProductResponse{ProductId: productId, Message: "Add product success"}, nil } func (s *server) DeleteProduct(ctx context.Context, request *pb.DeleteProductRequest) (*pb.EmptyResponse, error) { log.Printf("get request from client to add product,request is %s", request) productId := request.ProductId delete(dataBase, productId) return nil, nil } func (s *server) QueryProductInfo(ctx context.Context, request *pb.QueryProductRequest) (*pb.ProductInfoResponse, error) { log.Printf("get request from client fro query product info,%v", request) productId := request.ProductId product := dataBase[productId] response:=new(pb.ProductInfoResponse) response.ProductName = product.ProductName response.ProductId = product.ProductId response.ManufacturerId = product.ManufacturerId response.Weight = product.Weight response.ProductionDate = product.ProductionDate response.ImportDate = product.ImportDate return response, nil } func (s *server) QueryProductsInfo(ctx context.Context, request *pb.EmptyRequest) (*pb.ProductsInfoResponse, error) { // 待实现 return nil, nil } func main() { log.Printf("begin to start rpc server") lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterProductServiceServer(s, &server{}) // Register reflection service on gRPC server. reflection.Register(s) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
客户端实现
客户端非常的简单,就像gRPC介绍中一样,可以像调用本地方法一样调用远程gRPC服务,一个详细的例子如下:
package main import ( "log" "time" "golang.org/x/net/context" "google.golang.org/grpc" pb "grpc/servicedef/product" ) const ( address = "localhost:5230" ) func main() { // 建立一个与服务端的连接. conn, err := grpc.Dial(address, grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := pb.NewProductServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), time.Second) response,err := client.AddProduct(ctx,&pb.AddProductRequest{ProductName:"phone"}) if nil != err { log.Fatalf("add product failed, %v",err) } log.Printf("add product success,%s",response) productId:=response.ProductId queryResp,err :=client.QueryProductInfo(ctx,&pb.QueryProductRequest{ProductId: productId}) if nil !=err { log.Fatalf("query product info failed,%v",err) } log.Printf("Product info is %v",queryResp) defer cancel() }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 从0开始构建SpringCloud微服务(1)
- 从零开始构建企业级推荐系统
- 图解 BERT 模型:从零开始构建 BERT
- 从理解 Phoenix 索引源码开始,构建全文索引
- 从零开始构建Flink开发项目-Scala版
- 用webpack4从零开始构建react开发环境
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。