学习 Golang 并入门 gRPC
用golang创建一个使用gRPC的原型的步骤。
我将这篇文章作为参考,并且在写代码的时候参考了该文章。这篇文章的代码与上述文章相同。它还更清楚地指出了在哪里编写代码以及protoc命令。
我在使用gvm来管理Go的版本。
Go的版本是 go version go1.16.5 darwin/amd64。
请使用protoc命令,并在以下位置进行安装。
在以下方面,gRPC有哪些优点
项目的准备
我会制作一个合适的项目。
go mod init example.com/cat
我将安装必要的软件包。
go get -u google.golang.org/grpc
go get -u github.com/golang/protobuf/protoc-gen-go
可以创建这种类型的go.mod文件。
module example.com/cat
go 1.16
require (
github.com/golang/protobuf v1.5.2 // indirect
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
golang.org/x/sys v0.0.0-20210816032535-30e4713e60e3 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c // indirect
google.golang.org/grpc v1.40.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)
创建目录
请按以下方式创建文件夹和文件。
client/main.go
proto/cat.proto
server/main.go
service/main.go
首先,我们将proto/cat.proto写成以下格式。
syntax = "proto3";
option go_package = "./;pb";
package cat;
service Cat {
rpc GetMyCat (GetMyCatMessage) returns (MyCatResponse) {}
}
message GetMyCatMessage {
string target_cat = 1;
}
message MyCatResponse {
string name = 1;
string kind = 2;
}
关于 go_package 选项,需要将 package 的导入路径赋给 xx.proto 文件,可以通过执行 protoc 命令或在 .proto 文件中进行描述来实现。推荐的做法是写在 xx.proto 文件中。
相关链接:
– https://github.com/techschool/pcbook-go/issues/3#issuecomment-824040393
– https://blog.ebiiim.com/posts/grpc-with-go-mod/
请注意,以上提供的链接为活动URL。
代码自动生成
根据此proto/cat.proto文件,使用protoc命令自动生成gRPC代码。
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/cat.prot
生成客户端和服务器代码的方法可以在参考链接https://grpc.io/docs/languages/go/basics/#generating-client-and-server-code中找到。
使用这个命令
-
- proto/cat_grpc.pb.go
- proto/cat.pb.go
«生成后,proto/cat_grpc.pb.go文件中还会生成一个名为mustEmbedUnimplementedCatServer()的方法,其内容如下。»
type CatServer interface {
GetMyCat(context.Context, *GetMyCatMessage) (*MyCatResponse, error)
mustEmbedUnimplementedCatServer()
}
由于这个方法的存在,我无法运行这次参考的实现,所以我会稍微修改自动生成命令,以防止生成以上提到的方法。
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=require_unimplemented_servers=false:. --go-grpc_opt=paths=source_relative proto/cat.proto
请提供更多上下文的信息,这样我才能更好地进行翻译。
-
- https://github.com/grpc/grpc-go/issues/3794#issuecomment-725860916
- https://sat8bit.github.io/logs/daily-2021-01-28/
服务
package service
import (
"context"
"errors"
pb "example.com/cat/proto"
)
type MyCatService struct {
}
func (s *MyCatService) GetMyCat(ctx context.Context, message *pb.GetMyCatMessage) (*pb.MyCatResponse, error) {
switch message.TargetCat {
case "tama":
//たまはメインクーン
return &pb.MyCatResponse{
Name: "tama",
Kind: "mainecoon",
}, nil
case "mike":
//ミケはノルウェージャンフォレストキャット
return &pb.MyCatResponse{
Name: "mike",
Kind: "Norwegian Forest Cat",
}, nil
}
return nil, errors.New("Not Found YourCat")
}
func (s *MyCatService) UnimplementedGreeterServer() {}
客户 (kè hù)
package main
import (
"context"
"fmt"
"log"
pb "example.com/cat/proto"
"google.golang.org/grpc"
)
func main() {
//sampleなのでwithInsecure
conn, err := grpc.Dial("127.0.0.1:19003", grpc.WithInsecure())
if err != nil {
log.Fatal("client connection error:", err)
}
defer conn.Close()
client := pb.NewCatClient(conn)
message := &pb.GetMyCatMessage{TargetCat: "tama"}
res, err := client.GetMyCat(context.TODO(), message)
fmt.Printf("result:%#v \n", res)
fmt.Println("---------")
fmt.Printf("error::%#v \n", err)
}
服务器
package main
import (
"log"
"net"
"example.com/cat/service"
pb "example.com/cat/proto"
"google.golang.org/grpc"
)
func main() {
listenPort, err := net.Listen("tcp", ":19003")
if err != nil {
log.Fatalln(err)
}
server := grpc.NewServer()
catService := &service.MyCatService{}
// 実行したい実処理をseverに登録する
pb.RegisterCatServer(server, catService)
server.Serve(listenPort)
}
试一试
我会在终端中使用两个进程。
首先,我会把以下内容内化。
go run server/main.go
接下来,使用另一个进程访问服务器。
go run client/main.go
在client/main.go文件中,您可以看到以下的输出。
result:&pb.MyCatResponse{state:impl.MessageState{NoUnkeyedLiterals:pragma.NoUnkeyedLiterals{}, DoNotCompare:pragma.DoNotCompare{}, DoNotCopy:pragma.DoNotCopy{}, atomicMessageInfo:(*impl.MessageInfo)(0xc0000e5a08)}, sizeCache:0, unknownFields:[]uint8(nil), Name:"tama", Kind:"mainecoon"}
---------
error::<nil>
如果只想获取tama,请按以下方式进行更改。
fmt.Printf("result:%#v \n", res.Name)
请参阅
-
- https://note.com/dd_techblog/n/nb8b925d21118
-
- https://tech.smartcamp.co.jp/entry/grpc-and-protobuf-servey
- https://developers.google.com/protocol-buffers/docs/proto3#unknowns