Hello World GRPC的基本变化



我使用gRPCGolang

在成功运行他们的HelloWorld tutorial后,这需要我添加第二个功能,编译协议文件,我决定做一些进一步的改变。

包含了我的代码,它似乎不起作用,因为它期望pb变量是HelloWorld对象或其他东西,如命令行中的错误消息所示在下面。谁能告诉我,我哪里做错了,应该是一些非常小的变化。

我已经修复了我原来的帖子代码中的一些错别字。

命令行:

go run server/server.go
# command-line-arguments
server/server.go:24:71: undefined: helloworld.TheGRPCNotificationMessage

命令行协议文件:

protoc——go_out =。——go_opt = source_relative——go-grpc_out = =路径。——go-grpc_opt =路径= source_relative GRPCNotification/GRPCNotification.proto

GRPCNotification.proto

syntax = "proto3";
import "google/protobuf/empty.proto";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package grpcnotificationpackage;
// The greeting service definition.
service TheGRPCNotificationService {
// Sends a notification and nothing sent back
rpc SendNotificationWithGRPC (TheGRPCNotificationMessage) returns (google.protobuf.Empty);
// Receives a notification and does not reply
rpc ReceiveNotificationWithGRPC (stream TheGRPCNotificationMessage) returns (google.protobuf.Empty);
}
// The request notification message
message TheGRPCNotificationMessage {
string message = 1;
// ... add more here
}
// Since nothing gets returned from server we need this empty
message Empty {
// Nothing goes here
}

Client.go

// Package main implements a client for Greeter service.
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
address     = "localhost:50051"
defaultName = "world"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SendNotificationWithGRPC(ctx, &pb.TheGRPCNotificationMessage{Message: "Horse"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Sent a message, please check it reached server...")
}

Server.go

package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)

// server is used to implement helloworld.GreeterServer
type server struct {
pb.UnimplementedGreeterServer
}

// SendNotificationWithGRPC implements helloworld.GreeterServer   <--- Problem?
func (s *server) ReceiveNotificationWithGRPC(ctx context.Context, in *pb.TheGRPCNotificationMessage) {
log.Printf("Received: %v", in.Name)
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
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)
}
}

我希望示例教程没有把我这么粗略地粘在上面!

您的go_packageclient.goserver.go包导入不正确。这是一个"棘手的"问题。gRPC的一部分,但它的结果是因为协议必须支持许多(不同的)语言和他们的包解决方案。

你也重命名了服务和方法,所以不能使用例如GreeterService,因为它不再存在。大多数编辑器(例如VSCode)将帮助您导航包以查找命名错误。

pb "google.golang.org/grpc/examples/helloworld/helloworld"
  1. 假设你的代码是在一个叫做${REPO}的Go模块(可能是github.com/YOUR-ORG/YOUR-REPO的形式,即你:
go mod init ${REPO}
  1. 在原型文件中,对于Golang(我将把其他语言留给您解决),您需要:
option go_package = "${REPO}/helloworld";

注意${REPO}替换为github.com/....

  1. 我会鼓励你与原型包名称namegrpcnotificationpackage和你生成的代码包名称保持一致,但是,现在,你的原型包是grpcnotificationpackage,但你正在生成的代码为helloworld

  2. 在repo中创建名为helloworld的目录。你要求protoc生成Go源代码(go_package)到一个名为${REPO}/helloworld的包中,Go要求这些文件位于repo中名为helloworld的目录中。

  3. :

protoc 
--go_out=${PWD}/helloworld 
--go_opt=paths=source_relative 
--go-grpc_out=${PWD}/helloworld 
--go-grpc_opt=paths=source_relative 
GRPCNotification.proto

这个命令有各种各样的用法,但是这个命令将在你的repo中生成${PWD}/helloworld的源代码。

  1. 必须正确导入:
import (
...
${REPO}/helloworld
)
  1. 那么你必须更正你的参考文献。如果您调用服务TheGRPCNotificationService、方法SendNotificationWithGRPC和消息TheGRPCNotificationMessage,这就是协议将生成的内容(您可以查看生成的Go源代码来确认这一点)。所以:
package main
import (
"log"
"net"
pb "${REPO}/helloworld"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const (
port = ":50051"
)
// Ensure that `server` implements the interface
var _ pb.TheGRPCNotificationServiceServer = &server{}
// server is used to implement helloworld.GreeterServer
type server struct {
pb.UnimplementedTheGRPCNotificationServiceServer
}
// This is the correct signature of the method
func (s *server) ReceiveNotificationWithGRPC(
stream pb.TheGRPCNotificationService_ReceiveNotificationWithGRPCServer,
) error {
// Implement
return status.Errorf(codes.Unimplemented, "not implemented")
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterTheGRPCNotificationServiceServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
  1. 我不推荐returns (google.protobuf.Empty)。我不知道是否有最佳实践,但我认为最好返回一个不包含字段的消息,例如:
rpc Foo (FooRequest) returns (FooResponse);
message FooResponse {}
  1. 考虑使用gRPCurl等工具进行调试:

在本例中,gRPCurl使用proto而不是服务来枚举服务(在proto中定义):

grpcurl 
-plaintext 
--proto *.proto 
localhost:50051 list

收益率:

grpcnotificationpackage.TheGRPCNotificationService

相同,但适用于给定服务的方法:

grpcurl 
-plaintext 
--proto *.proto 
localhost:50051 list grpcnotificationpackage.TheGRPCNotificationService

产生以下方法:

grpcnotificationpackage.TheGRPCNotificationService.ReceiveNotificationWithGRPC
grpcnotificationpackage.TheGRPCNotificationService.SendNotificationWithGRPC

调用服务器流方法:

grpcurl 
-plaintext 
--proto *.proto 
localhost:50051 grpcnotificationpackage.TheGRPCNotificationService.ReceiveNotificationWithGRPC

产生(正确地说是一个未实现的错误)

ERROR:
Code: Unimplemented
Message: not implemented

最新更新