服务定义与编译
2026/1/15大约 3 分钟ProtobufService编译
服务定义与编译
一、服务定义
1.1 基本服务
syntax = "proto3";
package user;
option go_package = "example.com/pb/user";
// 用户服务
service UserService {
// 获取用户
rpc GetUser(GetUserRequest) returns (GetUserResponse);
// 创建用户
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
// 更新用户
rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
// 删除用户
rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
// 用户列表
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
}1.2 请求和响应消息
// 获取用户
message GetUserRequest {
int32 id = 1;
}
message GetUserResponse {
User user = 1;
}
// 创建用户
message CreateUserRequest {
string username = 1;
string email = 2;
string password = 3;
}
message CreateUserResponse {
User user = 1;
}
// 更新用户
message UpdateUserRequest {
int32 id = 1;
string username = 2;
string email = 3;
}
message UpdateUserResponse {
User user = 1;
}
// 删除用户
message DeleteUserRequest {
int32 id = 1;
}
message DeleteUserResponse {
bool success = 1;
}
// 用户列表
message ListUsersRequest {
int32 page = 1;
int32 page_size = 2;
}
message ListUsersResponse {
repeated User users = 1;
int32 total = 2;
}二、流式服务
2.1 服务端流
service FileService {
// 服务端流:下载文件
rpc DownloadFile(DownloadRequest) returns (stream FileChunk);
}
message DownloadRequest {
string filename = 1;
}
message FileChunk {
bytes data = 1;
int32 chunk_number = 2;
}2.2 客户端流
service FileService {
// 客户端流:上传文件
rpc UploadFile(stream FileChunk) returns (UploadResponse);
}
message UploadResponse {
string filename = 1;
int64 size = 2;
bool success = 3;
}2.3 双向流
service ChatService {
// 双向流:聊天
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}
message ChatMessage {
string user = 1;
string content = 2;
int64 timestamp = 3;
}三、编译命令
3.1 基本编译
# 只生成消息代码
protoc --go_out=. --go_opt=paths=source_relative \
user.proto
# 生成消息和 gRPC 代码
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
user.proto3.2 指定输出目录
# 输出到 pb 目录
protoc --go_out=./pb --go_opt=paths=source_relative \
--go-grpc_out=./pb --go-grpc_opt=paths=source_relative \
proto/user.proto3.3 多文件编译
# 编译多个文件
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
proto/*.proto3.4 指定 import 路径
protoc -I=proto -I=third_party \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
proto/user.proto四、生成的代码
4.1 消息代码(user.pb.go)
// 自动生成的代码
type User struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
}
func (x *User) GetId() int32 { ... }
func (x *User) GetUsername() string { ... }
func (x *User) GetEmail() string { ... }4.2 服务代码(user_grpc.pb.go)
// 客户端接口
type UserServiceClient interface {
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error)
CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error)
// ...
}
// 服务端接口
type UserServiceServer interface {
GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error)
CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error)
// ...
mustEmbedUnimplementedUserServiceServer()
}五、Makefile 自动化
5.1 完整 Makefile
PROTO_DIR := proto
PB_DIR := pb
.PHONY: proto clean
proto:
@mkdir -p $(PB_DIR)
protoc -I=$(PROTO_DIR) \
--go_out=$(PB_DIR) --go_opt=paths=source_relative \
--go-grpc_out=$(PB_DIR) --go-grpc_opt=paths=source_relative \
$(PROTO_DIR)/*.proto
clean:
rm -rf $(PB_DIR)/*.pb.go
# 安装依赖
install-tools:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest5.2 使用
make install-tools # 安装工具
make proto # 编译 proto 文件
make clean # 清理生成的文件六、项目结构
6.1 推荐结构
myproject/
├── proto/
│ ├── user.proto
│ ├── order.proto
│ └── common/
│ └── types.proto
├── pb/
│ ├── user.pb.go
│ ├── user_grpc.pb.go
│ ├── order.pb.go
│ ├── order_grpc.pb.go
│ └── common/
│ └── types.pb.go
├── server/
│ └── main.go
├── client/
│ └── main.go
├── Makefile
└── go.mod七、完整示例
7.1 user.proto
syntax = "proto3";
package user;
option go_package = "example.com/myapp/pb/user";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
// 用户
message User {
int32 id = 1;
string username = 2;
string email = 3;
string phone = 4;
UserStatus status = 5;
google.protobuf.Timestamp created_at = 6;
}
enum UserStatus {
USER_STATUS_UNSPECIFIED = 0;
USER_STATUS_ACTIVE = 1;
USER_STATUS_INACTIVE = 2;
}
// 用户服务
service UserService {
rpc GetUser(GetUserRequest) returns (User);
rpc CreateUser(CreateUserRequest) returns (User);
rpc UpdateUser(UpdateUserRequest) returns (User);
rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty);
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
rpc WatchUsers(google.protobuf.Empty) returns (stream User);
}
message GetUserRequest {
int32 id = 1;
}
message CreateUserRequest {
string username = 1;
string email = 2;
string phone = 3;
string password = 4;
}
message UpdateUserRequest {
int32 id = 1;
optional string username = 2;
optional string email = 3;
optional string phone = 4;
}
message DeleteUserRequest {
int32 id = 1;
}
message ListUsersRequest {
int32 page = 1;
int32 page_size = 2;
string keyword = 3;
UserStatus status = 4;
}
message ListUsersResponse {
repeated User users = 1;
int32 total = 2;
}7.2 编译
protoc -I=proto -I=/usr/local/include \
--go_out=pb --go_opt=paths=source_relative \
--go-grpc_out=pb --go-grpc_opt=paths=source_relative \
proto/user.proto八、常见问题
8.1 找不到 protoc-gen-go
# 确保 GOPATH/bin 在 PATH 中
export PATH="$PATH:$(go env GOPATH)/bin"
# 重新安装
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest8.2 import 路径错误
# 使用 -I 指定 import 路径
protoc -I=. -I=/usr/local/include proto/user.proto8.3 go_package 未设置
// 必须设置 go_package
option go_package = "example.com/myapp/pb";