[tldr] go使用gRPC

gRPC是谷歌推出的一个rpc服务框架, 数据编码采用protobuf实现.

安装环境

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

缺少可能导致出现可执行程序没有找到的报错, 可以参考stackoverflow的帖子

文件

syntax = "proto3";

option go_package = "./myproto";

package myproto;

message Hello {
  string name = 1;
}

service HelloService {
  rpc SayHello (Hello) returns (Hello);
}

分别需要messageservice2个部分的内容

编译

./bin/bin/protoc --go_out=. ./myproto/hello.proto
./bin/bin/protoc --go-grpc_out=. ./myproto/hello.proto

使用上述指令编译为符合grpc使用的服务, 一个是message的定义的GO实现, 一个是service的定义的GO实现

根据grpc官方文档应该采用类似以下的指令实现, 效果是一样的

protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    ./myproto/hello.proto
  • 本质是编译message和编译rpc的service

使用

以下代码为生成出来的go的grpc的服务的代码

// HelloServiceClient is the client API for HelloService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type HelloServiceClient interface {
	SayHello(ctx context.Context, in *Hello, opts ...grpc.CallOption) (*Hello, error)
}

type helloServiceClient struct {
	cc grpc.ClientConnInterface
}

func NewHelloServiceClient(cc grpc.ClientConnInterface) HelloServiceClient {
	return &helloServiceClient{cc}
}

func (c *helloServiceClient) SayHello(ctx context.Context, in *Hello, opts ...grpc.CallOption) (*Hello, error) {
	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
	out := new(Hello)
	err := c.cc.Invoke(ctx, HelloService_SayHello_FullMethodName, in, out, cOpts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

这些是自动生成的文件内容

Server

// HelloServiceServer is the server API for HelloService service.
// All implementations must embed UnimplementedHelloServiceServer
// for forward compatibility.
type HelloServiceServer interface {
	SayHello(context.Context, *Hello) (*Hello, error)
	mustEmbedUnimplementedHelloServiceServer()
}

以上代码是编译器自动生成的GO代码

Client

// HelloServiceClient is the client API for HelloService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type HelloServiceClient interface {
	SayHello(ctx context.Context, in *Hello, opts ...grpc.CallOption) (*Hello, error)
}

以上为自动编译生成的代码

启动服务

在自己编写的代码中使用上述生成的代码

可以参考go-grpc官方仓库样例代码

server

package main

import (
	"context"
	"fmt"
	"log"
	"myrpc/myproto"
	"net"

	"google.golang.org/grpc"
)

const (
	PORT = 1234
)

type Server struct {
	myproto.UnimplementedHelloServiceServer
}

func (s *Server) SayHello(ctx context.Context, in *myproto.Req) (*myproto.Res, error) {
	log.Printf("Received: %v", in.Name)
	return &myproto.Res{Message: "Hello " + in.Name}, nil
}

func main() {
	list, err := net.Listen("tcp", fmt.Sprintf(":%d", PORT))
	if err != nil {
		log.Printf("failed to listen: %v", err)
	}

	log.Printf("server listening at :%d", PORT)

	grpcServer := grpc.NewServer()
	myproto.RegisterHelloServiceServer(grpcServer, &Server{})
	grpcServer.Serve(list)
}

整体实现和常见的rpc类似

client

package main

import (
	"context"
	"fmt"
	"myrpc/myproto"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

const (
	PORT = 1234
)

func main() {
	conn, err := grpc.NewClient(fmt.Sprintf(":%d", PORT), grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	c := myproto.NewHelloServiceClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	res, err := c.SayHello(ctx, &myproto.Req{Name: "xuhe"})
	if err != nil {
		panic(err)
	}
	fmt.Println(res.GetMessage())
}

FQ

常见报错

panic: grpc: no transport security set (use grpc.WithTransportCredentials(insecure.NewCredentials()) explicitly or set credentials)

goroutine 1 [running]:
main.main()
        /home/xuhe/tmp/go/rpc/cmd/client/main.go:18 +0x1d4
exit status 2

需要手动设置为conn, err := grpc.NewClient(fmt.Sprintf(":%d", PORT), grpc.WithTransportCredentials(insecure.NewCredentials()))不安全的实现方式

参考

grpc使用GO官方文档

posted @ 2025-05-05 14:58  xuhe2  阅读(42)  评论(0)    收藏  举报