30-第一个grpc实现

45 阅读2分钟

demo 路劲如下

image.png

grpc 开发三步走

  1. 编写.proto 文件定义服务
  • 可以定义四种类型的服务方法:
    • 普通 rpc: Unary RPCs
    • 服务端流式 rpc: Server streaming RPCs
    • 客户端流式 rpc: Client streaming RPCs
    • 双向流式 rpc: Bidirectional streaming RPCs
syntax = "proto3";

package proto;

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloResponse);
}
  1. 使用 protoc 编译 .proto 文件生成 .pb.go 文件
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./pd/*.proto

3. 实现服务端和客户端(编写业务逻辑)

  • 服务端实现
// main.go
package main

import (
	"fmt"
	"net"
	"context"
	"hello_server/pd"
	"google.golang.org/grpc"
)
// grpc server
type server struct {
    pd.UnimplementedGreeterServer// 当你没有完全实现接口时,程序也是可以运行的
}

// 实现接口的标准格式
func (s *server) SayHello(ctx context.Context, in *pd.HelloRequest) (*pd.HelloResponse, error) {
    return &pd.HelloResponse{Reply: "Hello " + in.Name}, nil
}

func main() {
    // 启动服务
	lis, err := net.Listen("tcp", ":8091")
	if err != nil {
	    fmt.Printf("failed to listen: %v", err)
		return
	}
	s := grpc.NewServer()// 创建一个gRPC服务器
	pd.RegisterGreeterServer(s, &server{})// 注册服务

	// 启动服务
	err = s.Serve(lis)
	if err != nil {
		fmt.Printf("failed to serve: %v", err)
		return
	}
}
  • 客户端逻辑
  1. 也需要一份 .proto 文件
syntax = "proto3";// 版本声明

option go_package = "hello_client/proto"; // go_package go代码import路径

package pd;// 包声明,必须与server端一致

// 定义消息
message HelloRequest {
    string name = 1;// 字段序号
}

// 定义响应消息
message HelloResponse {
    string reply = 1;
}

// 定义服务
service Greeter {
    // 定义rpc方法 入参: HelloRequest  出参: HelloResponse
    rpc SayHello (HelloRequest) returns (HelloResponse);
}

注意:客户端和服务端都需要一份 .proto 文件

  • 生成 go 代码
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./proto/*.proto
package main

import (
	"log"
	"time"
	"context"
	pd "hello_client/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
    // 连接服务器
	conn, err := grpc.NewClient("localhost:8091", grpc.WithTransportCredentials(insecure.NewCredentials()))// grpc.WithInsecure():不使用安全传输
	if err != nil {
		log.Fatalf("did not connect: %v", err)
		return
	}
	defer conn.Close()// 关闭连接
	// 创建客户端
	c := pd.NewGreeterClient(conn)// GreeterClient是proto文件中定义的客户端
	// 调用服务
	// 执行RPC调用并打印收到的响应数据
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()// 取消上下文
	r, err := c.SayHello(ctx, &pd.HelloRequest{Name: "hello world"})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
		return
	}
	log.Printf("Greeting: %s", r.GetReply())// r.GetReply()是proto文件中定义的响应数据
}

启动 hello_server服务 再启动 hello_client服务

  • 如下:yes 成功了 image.png