Please enable Javascript to view the contents

使用 gRPC In Go

· ☕ 2 分钟 · 🐔 Redd Tsai
🏷️
  • #Go
  • RPC(Remote Procedure Call) 是一個電腦通訊協定,最早用在網路檔案系統上,透過該協定允許系統上的程式存取其它系統上的檔案。如今,如果你有接觸微服務,也常使用 RPC 來建立服務間的通訊。

    Define

    首先透過 Protocol Buffer 來定義 grpc service:
    sample.proto

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    syntax = "proto3";
    option go_package = ".;rpc";
    
    service SampleService {
        rpc SayHello (HelloRequest) returns (HelloReply) {}
    }  
    
    message HelloRequest {
        string name = 1;
    }
    
    message HelloReply {
        string message = 1;
    }
    

    編譯 sample.proto 生成 sample.pb.go:

    1
    
    protoc -I proto --go_out=plugins=grpc:pkg/gRPC proto/sample.proto 
    

    在 sample.pb.go 最上方可看到版本的訊息,往下可以看到剛剛所定義 SampleService:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    // Code generated by protoc-gen-go. DO NOT EDIT.
    // versions:
    // 	protoc-gen-go v1.25.0
    // 	protoc        v3.12.3
    // source: sample.proto
    
    // ~~~~ 略
    
    // SampleServiceServer is the server API for SampleService service.
    type SampleServiceServer interface {
    	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
    }
    
    // ~~~~ 略
    

    Server

    接著透過 sample.pb.go 來實作 grpc server,這裡定義一個 server 來繼承 SampleService 接口,並實作 SayHello 的內容:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    // ~~~~ 略
    
    func main() {
    	lis, err := net.Listen("tcp", ":6424")
    	if err != nil {
    		fmt.Println(err)
    	}
    	s := grpc.NewServer()
    	fmt.Println("grpc sample service ...")
    	rpc.RegisterSampleServiceServer(s, &server{})
    	if err := s.Serve(lis); err != nil {
    		fmt.Println(err)
    	}
    }
    
    type server struct {
    	rpc.SampleServiceServer
    }
    
    func (s *server) SayHello(ctx context.Context, in *rpc.HelloRequest) (*rpc.HelloReply, error) {
    	return &rpc.HelloReply{Message: "Hello " + in.GetName()}, nil
    }
    

    Client

    client 端也是使用相同的 protocol buffer 來呼叫 SayHello:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    func main() {
    	conn, err := grpc.Dial("0.0.0.0:6424", grpc.WithInsecure(), grpc.WithBlock())
    	if err != nil {
    		fmt.Println(err)
    	}
    	defer conn.Close()
    	c := rpc.NewSampleServiceClient(conn)
    	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    	defer cancel()
    	r, err := c.SayHello(ctx, &rpc.HelloRequest{Name: "redd"})
    	if err != nil {
    		fmt.Println(err)
    	}
    	fmt.Println(r.GetMessage())
    }
    

    Reference

    gRPC
    protobuf

    分享

    蔡文杰
    作者
    Redd Tsai
    Backend Developer