安装 protobuf

假设环境下已有protoc (protocal buffers compiler)。

对于 Go 语言,安装相应的可执行文件:

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

在Windows中,执行完安装命令后在C:\Users\user\go\bin路径下会有proctoc-gen-go.exeprotoc-gen-go-grpc.exe

安装完Go插件后,我们希望protoc生成Go语言的代码,需要为 .proto 文件加一行以指定生成的Go包名:

syntax = "proto3";
package com.example.pkg

option go_package = "example/gopkg"

如果需要使用 grpc 服务,安装包:

go get google.golang.org/grpc

之后便可启动一个 gRPC 服务器:

gRPC gateway

gRPC 服务生成面向 RestFul API 的网关

go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
syntax = "proto3";
package com.example.pkg
import "google/api/annotations.proto";

option go_package = "example/gopkg

service AuthService {
  rpc Login(LRequest) returns (LResponse) {
    option (google.api.http) = {
      post: "/v1/login"
      body: "*"
    };
  }

message LRequest {
  string field = 1;
}

message LResponse {
  string field = 1;
}

之后便可以生成grpc gateway的代码了:

protoc --go_out=. --go-grpc_out=. \
  --grpc-gateway_out=. \
  --openapiv2_out=. \
  greeter.proto

其所生成的文件含义如下:

  • greeter.pb.go: Protobuf message definitions.
  • greeter_grpc.pb.go: gRPC service definitions.
  • greeter.pb.gw.go: gRPC Gateway reverse-proxy code.
  • greeter.swagger.json: OpenAPI (Swagger) documentation.

gRPC 服务

package main

import (
	"context"
	"fmt"
	"log"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	pb "github.com/yourusername/yourproject/gen/go/hello"
)

type server struct {
	pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
	return &pb.HelloResponse{Message: fmt.Sprintf("Hello, %s!", req.Name)}, nil
}

func main() {
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	reflection.Register(s)

	log.Println("gRPC server is running on :50051")
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

gRPC 网关

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"google.golang.org/grpc"

	pb "github.com/yourusername/yourproject/gen/go/hello"
)

func runGateway() {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}

	err := pb.RegisterGreeterHandlerFromEndpoint(ctx, mux, "localhost:50051", opts)
	if err != nil {
		log.Fatalf("failed to register gateway: %v", err)
	}

	log.Println("gRPC Gateway is running on :8080")
	if err := http.ListenAndServe(":8080", mux); err != nil {
		log.Fatalf("failed to serve gateway: %v", err)
	}
}

func main() {
	go runGateway()

	// 启动 gRPC 服务
	runGRPCServer()
}