漏写 service 块会导致 protoc 不生成服务端接口和客户端 stub;必须显式定义 service 及其 rpc 方法,且参数返回值须为 message 类型,同时正确配置 go_package、及时注册服务、复用并关闭 ClientConn。

漏写 service 块,protoc 就不会生成服务端结构体或客户端 stub——这是 90% 的新手卡住的第一步。
proto 文件必须显式定义 service,否则没服务可跑
gRPC 不是靠 message 自动导出 RPC 的框架,它严格依赖 service 块来识别“哪些函数要暴露为远程方法”。没有它,protoc --go-out=. --go-grpc-out=. 只会生成数据结构(*.pb.go),但不会生成 *_grpc.pb.go 里的 XXXServer 接口和 RegisterXXXServer 函数。
- 错误写法:只写
message,不写service→ 生成代码里找不到RegisterGreeterServer - 正确写法:
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } - 注意
rpc方法的参数和返回值必须是已定义的message类型,不能直接用string或int32 -
option go_package = "example.com/myapp/proto;proto"要写对,否则生成的包路径错乱,import报错
RegisterXXXServer 必须在 grpc.NewServer() 后立即调用
服务注册不是“可选步骤”,而是运行前提。没注册,客户端能连上,但一调用就返回 rpc error: code = Unimplemented desc = Method not found。
- 必须调用由
protoc自动生成的pb.RegisterGreeterServer(s, &server{}),不是手写的、拼错的或大小写不一致的函数名 - 同一个
*grpc.Server实例上重复注册同一 service(比如两次RegisterGreeterServer)会 panic:duplicate registration - 拦截器(如日志、鉴权)要通过
grpc.UnaryInterceptor(...)选项传入grpc.NewServer(),不能注册完再“补加”
客户端别滥用 grpc.Dial(),*grpc.ClientConn 是长连接资源
每次 RPC 都 grpc.Dial() 看似简单,实则危险:连接风暴、文件描述符泄漏、DNS 缓存失效、连接堆积——生产环境必然崩。
立即学习“go语言免费学习笔记(深入)”;
- 应复用单个
*grpc.ClientConn,全局或按服务粒度管理 - 务必显式调用
conn.Close(),推荐defer conn.Close()(注意作用域,别在循环里 defer) - 连接时建议加基础选项:
grpc.WithInsecure()(开发)、grpc.WithTransportCredentials(credentials.NewTLS(...))(生产)、grpc.WithTimeout(5 * time.Second) - 不要硬编码
"localhost:50051",用配置或环境变量控制地址
真正难的不是写通第一个 SayHello,而是理解 gRPC 的契约本质:它不抽象网络,而是把“接口定义”当成第一公民。所有问题——生成失败、调用报 UNIMPLEMENTED、连接泄漏——几乎都源于对 .proto 结构、注册时机或连接生命周期的轻视。










