Go中如何跨语言实现传输? - GRPC

Go中如何跨语言实现传输? - GRPC

gRPC 是 Google 开源的高性能 RPC 框架,基于 HTTP/2 协议和 Protocol Buffers(Protobuf)序列化,支持多语言、流式传输和企业级特性。与 RESTful API 相比,它性能更高、接口定义更规范,特别适合微服务架构和跨语言服务调用。

概念 作用 说明
Protocol Buffers(Protobuf) 接口定义语言(IDL) 用于定义服务接口和消息结构,跨语言、跨平台,序列化性能极高
Service(服务) 定义 RPC 方法 .proto 文件中定义,包含方法名、请求消息、响应消息
Message(消息) 定义数据结构 类似于 Go 的结构体,用于定义请求和响应的数据格式
Unary RPC(一元 RPC) 最简单的 RPC 模式 客户端发送一个请求,服务端返回一个响应,类似传统的 HTTP 请求
Server Streaming RPC(服务端流式) 服务端流式返回 客户端发送一个请求,服务端返回多个响应
Client Streaming RPC(客户端流式) 客户端流式发送 客户端发送多个请求,服务端返回一个响应
Bidirectional Streaming RPC(双向流式) 双向流式传输 客户端和服务端可以同时发送和接收多个消息
bash 复制代码
# 1. 安装 protoc 编译器
# Mac 
brew install protobuf 
# Linux 
apt install -y protobuf-compiler

# 2. 安装 Go 插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 3. 安装 gRPC 核心库
go get google.golang.org/grpc

Unary RPC (一元 RPC)

plaintext 复制代码
grpc-demo/
├── proto/ 
│ └── user.proto # Protobuf 定义文件 
├── server/ 
│ └── main.go # gRPC 服务端
├── client/ 
│ └── main.go # gRPC 客户端 
└── go.mod

编写 Protobuf 定义(proto/user.proto

这是 gRPC 开发的核心,定义接口契约。

protobuf 复制代码
// 指定 Protobuf 版本 
syntax = "proto3"; 
// 指定生成的 Go 代码的包路径 
option go_package = "./proto"; 
// 定义包名 
package user;

// 定义消息(数据结构)
message User {
  uint32 id = 1; // 字段编号:1-15 占 1 字节,常用字段优先
  string username = 2;
  string email = 3;
}

message GetUserRequest {
  uint32 user_id = 1;
}

message GetUserResponse {
  User user = 1;
}

// 定义服务
service UserService {
  // 一元 RPC 方法
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
}
  • syntax = "proto3"; :指定使用 Protobuf v3 版本(推荐,比 v2 更简洁)。

  • option go_package = "./proto"; :指定生成的 Go 代码的包路径。

  • 消息字段编号:每个字段必须有唯一的编号,1-15 占 1 字节,16-2047 占 2 字节,常用字段建议用 1-15。

  • service Xxx { rpc Yyy(Req) returns (Resp) }:定义服务,包含多个 RPC 方法。

  • rpc 方法名(请求) returns (响应) :定义 RPC 方法。

  • message Xxx { type field = tag; }:定义消息结构,tag 必须唯一

bash 复制代码
protoc --go_out=. --go-grpc_out=. proto/user.proto

执行成功后,会在 proto/ 目录下生成两个文件:

  • user.pb.go:消息结构的 Go 代码
  • user_grpc.pb.go:服务接口的 Go 代码

服务端实现

go 复制代码
import (pb "grpc-demo/proto")

// 定义服务结构体,必须嵌入 Unimplemented*Server
type UserServer struct {
	pb.UnimplementedUserServiceServer // 必须嵌入,保证向前兼容
}

// 实现 Protobuf 中定义的 RPC 方法
func (s *UserServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
	// 核心业务逻辑:查询数据库等
	user := &pb.User{
		Id:       req.UserId,
		Username: "zhangsan",
		Email:    "zhangsan@example.com",
	}
	return &pb.GetUserResponse{User: user}, nil
}

func main() {
	// 监听端口
	lis, _ := net.Listen("tcp", ":50051")
	// 创建 gRPC 服务器
	s := grpc.NewServer()
	// 将服务实现注册到 gRPC 服务器
	pb.RegisterUserServiceServer(s, &UserServer{})
	// 启动服务,监听 TCP 连接
	s.Serve(lis)
}
  • type XxxServer struct { pb.UnimplementedXxxServer }:定义服务结构体,必须嵌入 Unimplemented

  • pb.UnimplementedUserServiceServer:必须嵌入这个结构体,确保向前兼容,即使后续服务添加了新方法,旧的服务端代码也不会报错。

  • 实现服务接口 :必须实现 .proto 文件中定义的所有 RPC 方法。

客户端实现

go 复制代码
import (pb "grpc-demo/proto")

func main() {
	// 连接服务端
	conn, _ := grpc.Dial(
		"localhost:50051",
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	)
	defer conn.Close()

	// 创建客户端
	client := pb.NewUserServiceClient(conn)

	// 调用 RPC 方法
	ctx := context.Background() // 空根上下文
	resp, _ := client.GetUser(ctx, &pb.GetUserRequest{UserId: 1})

	fmt.Printf("获取用户:%+v\n", resp.User)
}
  • client.Yyy(ctx, &Req{}):调用 RPC 方法

拦截器

拦截器类似 Gin 中间件,用于处理通用逻辑(日志、认证、限流)。

go 复制代码
// 日志拦截器
func LogInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
	// 请求前逻辑
	fmt.Printf("收到请求:%s\n", info.FullMethod)
	
	// 调用实际 RPC 方法
	resp, err := handler(ctx, req)
	
	// 请求后逻辑
	return resp, err
}

// 注册拦截器
func main() {
	lis, _ := net.Listen("tcp", ":50051")
	// 创建服务器时注册拦截器
	s := grpc.NewServer(grpc.UnaryInterceptor(LogInterceptor))
	pb.RegisterUserServiceServer(s, &UserServer{})
	s.Serve(lis)
}
  • grpc.NewServer(grpc.UnaryInterceptor(...)):创建 gRPC 服务器并注册拦截器
相关推荐
光电的一只菜鸡9 分钟前
为什么调整LSC会对AF产生影响
android·开发语言·kotlin
zhangjw3412 分钟前
第47篇:Java综合实战:电商秒杀系统(高并发场景)
java·开发语言
FOAF-lambda32 分钟前
uiautomation-new 控件方位的使用
开发语言·python
OKkankan36 分钟前
LangChain能力详解!:从工具调用到 LangSmith——让聊天模型具备实时交互能力!
开发语言·python·langchain
richard_yuu41 分钟前
AOI 实战第五篇:c_broken 漏检严重,V4 迭代背后的权衡
开发语言·深度学习·yolo
m0_734571761 小时前
深入理解C++ 析构函数<一>基本概念
开发语言·c++
滕州市燕猫虎计算机科技工作室个体工商户1 小时前
Java面试题汇总
java·开发语言
kaixin_learn_qt_ing2 小时前
model/view 筛选功能
qt
孙启超2 小时前
【AI开发之Rust】第 3 课:字符串与复合类型 —— 数据怎么放
开发语言·人工智能·后端·rust·llm·transformer