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

张开发
2026/4/6 5:03:18 15 分钟阅读

分享文章

Go中如何跨语言实现传输? - GRPC
Go中如何跨语言实现传输 - GRPCgRPC 是 Google 开源的高性能 RPC 框架基于 HTTP/2 协议和 Protocol BuffersProtobuf序列化支持多语言、流式传输和企业级特性。与 RESTful API 相比它性能更高、接口定义更规范特别适合微服务架构和跨语言服务调用。概念作用说明Protocol BuffersProtobuf接口定义语言IDL用于定义服务接口和消息结构跨语言、跨平台序列化性能极高Service服务定义 RPC 方法在.proto文件中定义包含方法名、请求消息、响应消息Message消息定义数据结构类似于 Go 的结构体用于定义请求和响应的数据格式Unary RPC一元 RPC最简单的 RPC 模式客户端发送一个请求服务端返回一个响应类似传统的 HTTP 请求Server Streaming RPC服务端流式服务端流式返回客户端发送一个请求服务端返回多个响应Client Streaming RPC客户端流式客户端流式发送客户端发送多个请求服务端返回一个响应Bidirectional Streaming RPC双向流式双向流式传输客户端和服务端可以同时发送和接收多个消息# 1. 安装 protoc 编译器# Macbrewinstallprotobuf# Linuxaptinstall-yprotobuf-compiler# 2. 安装 Go 插件goinstallgoogle.golang.org/protobuf/cmd/protoc-gen-golatest goinstallgoogle.golang.org/grpc/cmd/protoc-gen-go-grpclatest# 3. 安装 gRPC 核心库go get google.golang.org/grpcUnary RPC 一元 RPCgrpc-demo/ ├── proto/ │ └── user.proto # Protobuf 定义文件 ├── server/ │ └── main.go # gRPC 服务端 ├── client/ │ └── main.go # gRPC 客户端 └── go.mod编写 Protobuf 定义proto/user.proto这是 gRPC 开发的核心定义接口契约。// 指定 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 必须唯一protoc--go_out. --go-grpc_out. proto/user.proto执行成功后会在proto/目录下生成两个文件user.pb.go消息结构的 Go 代码user_grpc.pb.go服务接口的 Go 代码服务端实现import(pbgrpc-demo/proto)// 定义服务结构体必须嵌入 Unimplemented*ServertypeUserServerstruct{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:zhangsanexample.com,}returnpb.GetUserResponse{User:user},nil}funcmain(){// 监听端口lis,_:net.Listen(tcp,:50051)// 创建 gRPC 服务器s:grpc.NewServer()// 将服务实现注册到 gRPC 服务器pb.RegisterUserServiceServer(s,UserServer{})// 启动服务,监听 TCP 连接s.Serve(lis)}type XxxServer struct { pb.UnimplementedXxxServer }:定义服务结构体必须嵌入 Unimplementedpb.UnimplementedUserServiceServer必须嵌入这个结构体确保向前兼容即使后续服务添加了新方法旧的服务端代码也不会报错。实现服务接口必须实现.proto文件中定义的所有 RPC 方法。客户端实现import(pbgrpc-demo/proto)funcmain(){// 连接服务端conn,_:grpc.Dial(localhost:50051,grpc.WithTransportCredentials(insecure.NewCredentials()),)deferconn.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 中间件用于处理通用逻辑日志、认证、限流。// 日志拦截器funcLogInterceptor(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)// 请求后逻辑returnresp,err}// 注册拦截器funcmain(){lis,_:net.Listen(tcp,:50051)// 创建服务器时注册拦截器s:grpc.NewServer(grpc.UnaryInterceptor(LogInterceptor))pb.RegisterUserServiceServer(s,UserServer{})s.Serve(lis)}grpc.NewServer(grpc.UnaryInterceptor(...)):创建 gRPC 服务器并注册拦截器

更多文章