gRPC's gRPC development process and entry cases

1. gRPC development process

gRPCThe general development process is as follows:

1. Define the proto file, that is, define the Request and Response structures, and the service Service that contains multiple methods.

2. Use the protoc tool to generate a Stub for the corresponding language.

3. The server implements the interface defined in proto and writes logic codes.

4. The client calls the server through the generated Stub.

1.1 Write .proto description file

Go writes an rpc interface to obtain server time. time.protoThe content of the file is as follows:

syntax = "proto3";
package proto;
option go_package = "./base;base";

service BaseService {
    rpc GetTime (TimeRequest) returns (TimeResponse) {}
}

message TimeRequest {}

message TimeResponse {
    string time = 1;
}

1.2 Compile and generate .pb.go file

Generate the Stub code of the server and the client through protoc:

$ protoc --go_out=plugins=grpc:. time.proto

1.3 The server implements the agreed interface and provides services

Write server.gothe file:

package main

import (
	"context"
	pb "demo/base"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"net"
	"time"
)

type service struct {
    
    
	// time.pb.go中的结构体
	pb.UnimplementedBaseServiceServer
}

func main() {
    
    
	listen, err := net.Listen("tcp", ":50051")
	fmt.Println("Listen 50051!")
	if err != nil {
    
    
		fmt.Println(err)
	}
	s := grpc.NewServer()
	reflection.Register(s)
	pb.RegisterBaseServiceServer(s, &service{
    
    })
	s.Serve(listen)
}

// 实现接口
func (s *service) GetTime(ctx context.Context, in *pb.TimeRequest) (*pb.TimeResponse, error) {
    
    
	now := time.Now().Format("2006-01-02 15:04:05")
	return &pb.TimeResponse{
    
    Time: now}, nil
}
# 启动server
$ go run server.go
Listen 50051!

1.4 The client calls the method in the .pb.go file to request the service according to the agreement

Write client.gothe file:

package main

import (
	"context"
	pb "demo/base"
	"fmt"
	"google.golang.org/grpc"
	"time"
)

func main() {
    
    
	conn, err := grpc.Dial(":50051", grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
    
    
		fmt.Println(err)
	}
	defer conn.Close()
	c := pb.NewBaseServiceClient(conn)
	getTime(c)
}

func getTime(client pb.BaseServiceClient) error {
    
    
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, _ := client.GetTime(ctx, &pb.TimeRequest{
    
    })
	fmt.Println("Time:", r.Time)
	return nil
}
# 启动client
$ go run client.go
Time: 2023-02-10 16:14:01

Final project structure:

$ tree demo
demo
├── base
│   └── time.pb.go
├── client.go
├── go.mod
├── go.sum
├── server.go
└── time.proto

1 directory, 6 files

2. gRPC entry case

By convention, here also starts with a Hello project, this project defines a Hello Service, the client sends a request containing a string name,

The server returns a Hello message.

2.1 Step1: Write the description file hello.proto

// 指定proto版本
// 表明使用proto3语法,如果你没有指定这个,编译器会使用proto2语法
syntax = "proto3"; 
// 指定默认包名
package hello;     
// 指定golang包名
option go_package = "./hello";
// 定义Hello服务
service Hello {
    // 定义SayHello方法
    rpc SayHello(HelloRequest) returns (HelloResponse) {}
}
// HelloRequest 请求结构
message HelloRequest {
    string name = 1;
}
// HelloResponse 响应结构
message HelloResponse {
    string message = 1;
}

hello.protoA Hello Service is defined in the file, which contains a SayHellomethod and declares HelloRequestand

HelloResponseMessage structures are used for requests and responses. The client calls the method HelloRequestwith parameters SayHelloto request the server, and the server

The server responds to HelloResponsethe message. A simple service is defined.

2.2 Step2: Compile and generate .pb.go file

# 编译hello.proto
$ protoc -I . --go_out=plugins=grpc:. ./hello.proto

The file generated in the current directory hello.pb.go, according to .protothe instructions in the file, contains the description of the server interface HelloServer, the client

Port interface and implementation HelloClient, and HelloRequeststructure HelloResponse.

2.3 Step3: Implement the server interface server.go

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	// 引入编译生成的包
	pb "demo/hello"
	"google.golang.org/grpc"
)

const (
	// Address gRPC服务地址
	Address = ":50052"
)

type server struct {
    
    
	pb.UnimplementedHelloServer
}

// SayHello 实现Hello服务接口
func (s* server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
    
    
	resp := new(pb.HelloResponse)
	resp.Message = fmt.Sprintf("Hello %s.", in.Name)
	return resp, nil
}

func main() {
    
    
	listen, err := net.Listen("tcp", Address)
	log.Println("Listen ", Address)
	if err != nil {
    
    
		log.Fatalf("Failed to listen: %v", err)
	}
	// 实例化 grpc Server
	s := grpc.NewServer()
	// 注册HelloService
	pb.RegisterHelloServer(s, &server{
    
    })
	if err := s.Serve(listen); err != nil {
    
    
		log.Fatalf("failed to serve: %v", err)
	}
}

Instantiate grpc Server and register HelloService to start providing services.

# 启动服务
$ go run server.go
2023/02/10 18:26:39 Listen  :50052

2.4 Step4: Implement the client to call client.go

package main

import (
	pb "demo/hello" // 引入proto包
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"log"
)

const (
	// Address gRPC服务地址
	Address = ":50052"
)

func main() {
    
    
	// 连接
	conn, err := grpc.Dial(Address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
    
    
		log.Fatalln(err)
	}
	defer conn.Close()
	// 初始化客户端
	c := pb.NewHelloClient(conn)
	// 调用方法
	req := &pb.HelloRequest{
    
    Name: "gRPC"}
	res, err := c.SayHello(context.Background(), req)
	if err != nil {
    
    
		log.Fatalln(err)
	}
	log.Println(res.Message)
}

After the client initializes the connection, it can directly call the method hello.pb.goimplemented in SayHelloto initiate a request to the server. The usage posture is like calling

Same with native methods.

# 启动客户端
$ go run client.go
2023/02/10 18:30:08 Hello gRPC.

If you get Hello gRPCa reply, the demo is running successfully.

# 项目结构
$ tree demo
demo
├── client.go
├── go.mod
├── go.sum
├── hello
│   └── hello.pb.go
├── hello.proto
└── server.go

1 directory, 6 files

Guess you like

Origin blog.csdn.net/qq_30614345/article/details/132050885