首先定义数据结构,保存为.proto文件
syntax = "proto3";
package tutorial;
// The protocol compiler generates a class from the following .proto file with
// methods for writing and reading the message fields. The class is called
// "Person" and is in a package called "tutorial". You can specify a different
// class name using the java_outer_classname option.
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}
然后,用protocol buffer编译器以生成go语言源代码。没想多遇见了好几次问题。当然,已经有现成且有效的解决方案了。
编译指令:
protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto
首先报错的是,没有protoc-gen-go。于是百度,搜到了下面这篇博客。
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
没有程序,首先就要安装。使用上条指令安装后,需要手动复制protoc-gen-go.exe到proto的bin路径下。
随后,又执行上面的编译指令,就出现了下面的问题。
protoc-gen-go: unable to determine Go import path for "person.proto"
Please specify either:
• a "go_package" option in the .proto source file, or
• a "M" argument on the command line.
See https://protobuf.dev/reference/go/go-generated#package for more information.
解决方案是在proto文件中添加一行
option go_package="/main";也就是需要自己设定生成的pb.go的包名
解决方案,这篇博客非常详细,清楚,也可以直接查看。
main.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
"io/ioutil"
"log"
"net"
"protoTest/calculator"
"protoTest/person"
)
const fileName = "D:\\protoTest\\main\\addressbook.data"
func testProc() {
in, err := ioutil.ReadFile(fileName)
if err != nil {
log.Fatalln("Error reading file:", err)
}
book := &person.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
// Add an address.
book.People = append(book.People, &person.Person{
Name: "Alice",
Id: 100,
Email: "[email protected]",
})
// Write the new address book back to disk.
out, err := proto.Marshal(book)
if err != nil {
log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(fileName, out, 0644); err != nil {
log.Fatalln("Failed to write address book:", err)
}
fmt.Println("that is ok")
}
func main() {
testProc()
}
通过简短的例子和bing的解释,大致了解了protobuf的优势。以二进制的方式压缩数据,在传输过程中就能节省资源,减轻网络负荷。
例子比较简易,然后就想试一下protobuf在grpc中的使用,就有了下面的例子。
calculator.proto
package calculator;
// The calculator service definition.
service Calculator {
// Sends two integers and returns their sum
rpc Add (AddRequest) returns (AddResponse) {}
// Sends two integers and returns their difference
rpc Subtract (SubtractRequest) returns (SubtractResponse) {}
// Sends two integers and returns their product
rpc Multiply (MultiplyRequest) returns (MultiplyResponse) {}
// Sends two integers and returns their quotient
rpc Divide (DivideRequest) returns (DivideResponse) {}
}
// The request message containing two integers
message AddRequest {
int32 a = 1;
int32 b = 2;
}
// The response message containing the sum
message AddResponse {
int32 result = 1;
}
// The request message containing two integers
message SubtractRequest {
int32 a = 1;
int32 b = 2;
}
// The response message containing the difference
message SubtractResponse {
int32 result = 1;
}
// The request message containing two integers
message MultiplyRequest {
int32 a = 1;
int32 b = 2;
}
// The response message containing the product
message MultiplyResponse {
int32 result = 1;
}
// The request message containing two integers
message DivideRequest {
int32 a = 1;
int32 b = 2;
}
// The response message containing the quotient
message DivideResponse {
int32 result = 1;
}
protoc -I=D:\Git\protoTest\protobuf --go_out=D:\Git\protoTest calculator.proto
没注意,以为都是用protoc-gen-go.exe就好了呢。直接编译,还是生成了一堆文件,没有报错。
但是,发觉和官方给的例子差异很大。比如,官方的helloworld例子,我直接看的在线代码,里面proto生成的pb.go包含客户端和服务器的部分,但是我的pb.go文件就没有。我还觉得很奇怪呢,但还是有样学样的,添加一些代码,终于改好了client。于是开始改server端,但是太麻烦了,越改越觉得离谱。于是重新看了下bing给我的编译指令,和我这个可差太远了。才意识到问题所在。
protoc calculator.proto --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative
使用这个指令编译,遇见的问题,就是类似于上面的,没有protoc-gen-go-grpc。
于是有样学样,安装就好了。
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
同理,安装后需要复制protoc-gen-go-grpc.exe到protoc的bin路径下。
然后就可以正常编译了。
protoc calculator.proto --go_out=.. --go-grpc_out=.. //修改了生成文件保存的路径。
server.go
package main
import (
"context"
"grpcTest/calculator"
)
type Server struct {
calculator.UnimplementedCalculatorServer
}
// Add implements the Add rpc method
func (s *Server) Add(ctx context.Context, in *calculator.AddRequest) (*calculator.AddResponse, error) {
// Get the two integers from the request
a := in.GetA()
b := in.GetB()
// Compute the sum
result := a + b
// Return the response with the sum
return &calculator.AddResponse{Result: result}, nil
}
func (s *Server) Subtract(ctx context.Context, in *calculator.SubtractRequest) (*calculator.SubtractResponse, error) {
// Get the two integers from the request
a := in.GetA()
b := in.GetB()
// Compute the sum
result := a - b
// Return the response with the sum
return &calculator.SubtractResponse{Result: result}, nil
}
func (s *Server) Multiply(ctx context.Context, in *calculator.MultiplyRequest) (*calculator.MultiplyResponse, error) {
// Get the two integers from the request
a := in.GetA()
b := in.GetB()
// Compute the sum
result := a * b
// Return the response with the sum
return &calculator.MultiplyResponse{Result: result}, nil
}
func (s *Server) Divide(ctx context.Context, in *calculator.DivideRequest) (*calculator.DivideResponse, error) {
// Get the two integers from the request
a := in.GetA()
b := in.GetB()
// Compute the sum
result := a / b
// Return the response with the sum
return &calculator.DivideResponse{Result: result}, nil
}
client.go
package main
import (
"context"
"google.golang.org/grpc"
"grpcTest/calculator"
)
type Client struct {
conn *grpc.ClientConn
}
// NewClient creates a new Client with the given connection
func NewClient(conn *grpc.ClientConn) *Client {
return &Client{conn: conn}
}
// Add calls the Add rpc method with two integers and returns their sum
func (c *Client) Add(a, b int32) (int32, error) {
// Create a new CalculatorClient with the connection
//client := NewCalculatorClient(c.conn)
client := calculator.NewCalculatorClient(c.conn)
// Create a new AddRequest with the two integers
req := &calculator.AddRequest{A: a, B: b}
// Call the Add method with the request and get the response
res, err := client.Add(context.Background(), req)
if err != nil {
return 0, err
}
// Return the result from the response
return res.GetResult(), nil
}
func (c *Client) Subtract(a, b int32) (int32, error) {
// Create a new CalculatorClient with the connection
//client := NewCalculatorClient(c.conn)
client := calculator.NewCalculatorClient(c.conn)
// Create a new AddRequest with the two integers
req := &calculator.SubtractRequest{A: a, B: b}
// Call the Add method with the request and get the response
res, err := client.Subtract(context.Background(), req)
if err != nil {
return 0, err
}
// Return the result from the response
return res.GetResult(), nil
}
func (c *Client) Multiply(a, b int32) (int32, error) {
// Create a new CalculatorClient with the connection
//client := NewCalculatorClient(c.conn)
client := calculator.NewCalculatorClient(c.conn)
// Create a new AddRequest with the two integers
req := &calculator.MultiplyRequest{A: a, B: b}
// Call the Add method with the request and get the response
res, err := client.Multiply(context.Background(), req)
if err != nil {
return 0, err
}
// Return the result from the response
return res.GetResult(), nil
}
func (c *Client) Divide(a, b int32) (int32, error) {
// Create a new CalculatorClient with the connection
//client := NewCalculatorClient(c.conn)
client := calculator.NewCalculatorClient(c.conn)
// Create a new AddRequest with the two integers
req := &calculator.DivideRequest{A: a, B: b}
// Call the Add method with the request and get the response
res, err := client.Divide(context.Background(), req)
if err != nil {
return 0, err
}
// Return the result from the response
return res.GetResult(), nil
}
// Close closes the connection
func (c *Client) Close() error {
return c.conn.Close()
}
main.go
package main
import (
"context"
"google.golang.org/grpc"
"grpcTest/calculator"
"log"
"net"
)
const address = "localhost:50051"
const (
// Port on which the server listens.
port = ":50051"
)
func testServer(c chan bool) {
// Listen on a port
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Create a new gRPC server
s := grpc.NewServer()
// Register a new Calculator service with the server
calculator.RegisterCalculatorServer(s, &Server{})
c <- true
log.Println("server listening at :50051")
// Serve gRPC requests on the port
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func test() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Create a new gRPC server
s := grpc.NewServer()
// Register a new Calculator service with the server
calculator.RegisterCalculatorServer(s, &Server{})
log.Println("server listening at :50051")
// Serve gRPC requests on the port
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {
test()
return
//testProc()
ch := make(chan bool)
go testServer(ch)
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
// Create a calculator client
c := calculator.NewCalculatorClient(conn)
// Call the Add method with two integers
r, err := c.Add(context.Background(), &calculator.AddRequest{A: 3, B: 5})
if err != nil {
log.Fatalf("could not add: %v", err)
}
// Print the result
log.Printf("The sum is: %d", r.GetResult())
r1, err := c.Subtract(context.Background(), &calculator.SubtractRequest{A: 3, B: 5})
if err != nil {
log.Fatalf("could not add: %v", err)
}
// Print the result
log.Printf("The sum is: %d", r1.GetResult())
r2, err := c.Multiply(context.Background(), &calculator.MultiplyRequest{A: 3, B: 5})
if err != nil {
log.Fatalf("could not add: %v", err)
}
// Print the result
log.Printf("The sum is: %d", r2.GetResult())
r3, err := c.Divide(context.Background(), &calculator.DivideRequest{A: 13, B: 5})
if err != nil {
log.Fatalf("could not add: %v", err)
}
// Print the result
log.Printf("The sum is: %d", r3.GetResult())
}
过程中缺什么包啥的,直接go get就好了。一执行,还是没有任何问题的。
这是目录结构:
于是又想着,protobuf是可以支持不同平台的。所以还想弄个python请求go的例子
没想到处处碰壁,python/Java/C++/node。都很困难。暂时就先不弄了。
标签:int32,protobuf,err,grpc,calculator,go,message From: https://www.cnblogs.com/dayq/p/17453267.html