3. Go语言gRPC环境搭建:模块初始化、protoc编译器与插件配置
搭建gRPC开发环境是进入微服务通信优化的第一步。本章将引导你完成Go模块初始化、protoc编译器安装、protoc-gen-go插件配置,并运行第一个gRPC服务端与客户端。环境就绪后,后续章节的并发建模与性能优化才能落地。
3.1 环境全景:工具链与依赖关系
gRPC-Go开发依赖三个核心层次:协议编译器(protoc)、Go代码生成插件、gRPC运行时库。下图展示了各组件之间的协作关系。
3.2 Go模块初始化
从Go 1.16开始,go mod是官方推荐的依赖管理方式。gRPC-Go项目必须使用Go Modules管理依赖版本。
操作步骤:
- 创建项目目录并进入
- 执行
go mod init初始化模块 - 后续通过
go get拉取gRPC依赖
mkdir grpc-demo && cd grpc-demo
go mod init github.com/yourname/grpc-demo
模块名建议使用完整的仓库路径,避免与标准库冲突。初始化后目录下会生成 go.mod 文件。
3.3 protoc编译器安装
protoc是Protocol Buffers的官方编译器,负责将 .proto 文件编译成目标语言代码。不同操作系统安装方式如下:
| 操作系统 | 安装方式 | 验证命令 |
|---|---|---|
| macOS | brew install protobuf |
protoc --version |
| Ubuntu/Debian | apt install protobuf-compiler |
protoc --version |
| Windows | 从GitHub Releases下载预编译包,加入PATH | protoc --version |
| 手动安装 | 从 protobuf releases 下载对应平台压缩包 | 解压后将 bin/protoc 加入PATH |
版本建议:推荐使用 protoc 3.21.x 或更高版本。低版本可能不支持最新的proto3语法特性,如 optional 关键字。
3.4 protoc-gen-go与protoc-gen-go-grpc插件配置
protoc本身不生成Go代码,需要安装两个专用插件:
- protoc-gen-go:生成消息类型的Go结构体(
*.pb.go) - protoc-gen-go-grpc:生成gRPC服务端和客户端桩代码(
*_grpc.pb.go)
使用 go install 安装到 $GOPATH/bin:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
安装后确认插件在PATH中:
which protoc-gen-go
which protoc-gen-go-grpc
常见错误:如果 protoc 找不到插件,会报错 protoc-gen-go: program not found or is not executable。请确保 $GOPATH/bin 已加入系统PATH环境变量。
3.5 编写第一个proto文件
在项目根目录创建 proto/hello.proto:
syntax = "proto3";
package hello;
option go_package = "github.com/yourname/grpc-demo/proto/hello";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
关键字段说明:
syntax = "proto3":使用proto3语法option go_package:指定生成的Go包路径,必须与模块路径对应service Greeter:定义一个gRPC服务,包含一个RPC方法
3.6 编译proto文件生成Go代码
在项目根目录执行编译命令:
protoc --go_out=. --go-grpc_out=. proto/hello.proto
执行后生成两个文件:
proto/hello/hello.pb.go— 消息类型代码proto/hello/hello_grpc.pb.go— 服务端/客户端桩代码
生成的目录结构如下:
grpc-demo/
├── go.mod
├── go.sum
├── proto/
│ ├── hello.proto
│ └── hello/
│ ├── hello.pb.go
│ └── hello_grpc.pb.go
3.7 第一个gRPC服务端
创建 server/main.go:
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "github.com/yourname/grpc-demo/proto/hello"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("收到请求: %v", req.GetName())
return &pb.HelloReply{Message: "Hello, " + req.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("监听失败: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Println("gRPC服务端启动于 :50051")
if err := s.Serve(lis); err != nil {
log.Fatalf("服务失败: %v", err)
}
}
3.8 第一个gRPC客户端
创建 client/main.go:
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "github.com/yourname/grpc-demo/proto/hello"
)
func main() {
conn, err := grpc.Dial("localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("连接失败: %v", err)
}
defer conn.Close()
client := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "gRPC"})
if err != nil {
log.Fatalf("调用失败: %v", err)
}
log.Printf("收到响应: %v", resp.GetMessage())
}
3.9 运行验证
启动服务端和客户端,验证通信是否正常:
# 终端1:启动服务端
go run server/main.go
# 输出: gRPC服务端启动于 :50051
# 终端2:运行客户端
go run client/main.go
# 输出: 收到响应: Hello, gRPC
验证要点:
- 服务端日志显示
收到请求: gRPC - 客户端日志显示
收到响应: Hello, gRPC - 两端无panic或连接拒绝错误
3.10 环境搭建检查清单
| 检查项 | 验证方式 | 预期结果 |
|---|---|---|
| Go版本 | go version |
≥ 1.18 |
| protoc版本 | protoc --version |
≥ 3.21.0 |
| protoc-gen-go | which protoc-gen-go |
路径存在 |
| protoc-gen-go-grpc | which protoc-gen-go-grpc |
路径存在 |
| gRPC依赖 | go list -m google.golang.org/grpc |
版本 ≥ 1.50.0 |
| 服务端启动 | go run server/main.go |
无报错,监听 :50051 |
| 客户端调用 | go run client/main.go |
收到正确响应 |