gRPC服务必须用.proto文件定义并生成代码,且需正确注册、嵌入基类、按序启动;否则服务不可用。具体包括:用protoc生成.pb.go和_grpc.pb.go;实现结构体嵌入UnimplementedXXXServer;RegisterXXXServer须在grpc.Server.Serve()前调用。

gRPC服务定义必须用 .proto 文件,不能靠手写 Go 接口;否则客户端调不通、服务端收不到请求,连 UNIMPLEMENTED 错误都可能不报——因为根本没注册上。
proto 文件里 service 块必须和生成命令严格对应
你写 service UserService,生成的 Go 代码里就会有 RegisterUserServiceServer 和 UserServiceServer 接口。如果 proto 里写成 service UserSvc,但代码里还按 UserService 去注册,编译会报 undefined: RegisterUserServiceServer。
-
protoc命令必须同时带--go_out和--go-grpc_out,缺一不可 - 推荐加
--go-grpc_opt=paths=source_relative,避免因go_package路径嵌套导致导入错乱 - 检查生成结果:必须看到两个文件 ——
user.pb.go(含消息结构)和user_grpc.pb.go(含RegisterXXXServer函数)
Go 服务实现体必须嵌入 UnimplementedXXXServer
gRPC 不靠方法名或反射匹配实现,只认类型继承关系。哪怕你把所有 RPC 方法都写全了,只要没嵌入基类,RegisterUserServiceServer 就会拒绝接收你的实例。
- 正确写法:
type UserService struct{ pb.UnimplementedUserServiceServer }(其中pb是你 import 的 proto 包别名) - 嵌入后可以只重写需要的方法,其余留空——未实现方法默认 panic,适合开发期快速验证
- 不嵌入会导致运行时报
cannot assign *UserService to UserServiceServer,错误信息非常隐蔽
RegisterXXXServer 必须在 grpc.Server.Serve() 之前调用
这是最常被忽略的启动顺序问题。server 实例创建出来是空的,不注册就等于没挂任何服务,客户端连接后发请求,只会收到 UNIMPLEMENTED 状态码,且服务端日志通常不打任何提示。
立即学习“go语言免费学习笔记(深入)”;
- 典型正确顺序:
srv := grpc.NewServer()→pb.RegisterUserServiceServer(srv, &UserService{})→lis, _ := net.Listen("tcp", ":8080")→srv.Serve(lis) - 一旦
srv.Serve()开始运行,后续再调RegisterXXXServer完全无效 - 多个 service 注册时,顺序无关,但都必须在
Serve()前完成
真正卡住人的从来不是语法,而是 RegisterXXXServer 没调、UnimplementedXXXServer 没嵌、或者 user_grpc.pb.go 根本没生成出来——这三个点漏掉任何一个,服务看起来“跑起来了”,实际就是个哑巴。


















