Go中使用 Protobuf 初体验

什么是 Protobuf

Protocol Buffers(简称 Protobuf)是由 Google 开发的一种轻便高效的结构化数据存储格式,用于在不同语言之间序列化和反序列化数据。它被广泛应用于 RPC(远程过程调用)系统和数据存储系统中。

Protobuf 的核心理念是定义 .proto 文件,这个文件描述了数据结构。通过编译 .proto 文件,可以生成不同编程语言的代码,用于读写这些数据结构。

Protobuf 的优势

  • 高效:二进制格式比文本格式(如 JSON、XML)更小、更快。
  • 跨语言:支持多种编程语言,如 C++、Java、Python、Go 等。
  • 兼容性:支持向后兼容,可以在不影响旧代码的情况下添加新的字段。

项目结构和实操例子

以下是一个简单的 Protobuf 和 Go 的实操例子,展示了如何定义、编译和使用 Protobuf。

项目结构

go 复制代码
your_project/
├── proto/
│   └── user.proto
├── server/
│   └── server.go
├── client/
│   └── client.go
└── go.mod

步骤 1: 创建项目结构

sh 复制代码
mkdir -p your_project/{proto,server,client}
cd your_project
go mod init example.com/your_project

步骤 2: 定义 user.proto 文件

your_project/proto 目录中创建 user.proto 文件:

go 复制代码
syntax = "proto3";

package user;

option go_package = "./proto";

service UserService {
    rpc GetUser (GetUserRequest) returns (GetUserResponse);
}

message GetUserRequest {
    int32 id = 1;
}

message GetUserResponse {
    User user = 1;
}

message User {
    int32 id = 1;
    string name = 2;
    string email = 3;
}

步骤 3: 安装 Protobuf 编译器和插件

确保你已经安装了 Protobuf 编译器 protoc。你可以从 Protobuf Releases 页面下载相应的版本。

然后安装 protoc-gen-goprotoc-gen-go-grpc 插件:

sh 复制代码
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

步骤 4: 编译 Protobuf 文件

your_project 目录下运行以下命令生成 Go 代码:

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

这会在 proto 目录中生成 user.pb.gouser_grpc.pb.go 文件。

步骤 5: 实现服务器

your_project/server 目录中创建 server.go 文件:

go 复制代码
package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "example.com/your_project/proto"
)

type server struct {
    pb.UnimplementedUserServiceServer
}

func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
    user := &pb.User{
        Id:    req.Id,
        Name:  "John Doe",
        Email: "johndoe@example.com",
    }
    return &pb.GetUserResponse{User: user}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    grpcServer := grpc.NewServer()
    pb.RegisterUserServiceServer(grpcServer, &server{})
    log.Println("Server is running on port 50051")
    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

步骤 6: 实现客户端

your_project/client 目录中创建 client.go 文件:

go 复制代码
package main

import (
    "context"
    "log"
    "time"

    "google.golang.org/grpc"
    pb "example.com/your_project/proto"
)

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    client := pb.NewUserServiceClient(conn)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    req := &pb.GetUserRequest{Id: 1}
    res, err := client.GetUser(ctx, req)
    if err != nil {
        log.Fatalf("could not get user: %v", err)
    }
    log.Printf("User: %v", res.User)
}

运行步骤

运行服务器

  1. 打开一个终端窗口。
  2. 导航到 your_project/server 目录。
  3. 运行以下命令:
sh 复制代码
go run server.go

你应该会看到服务器正在监听端口 50051。

运行客户端

  1. 打开另一个终端窗口。
  2. 导航到 your_project/client 目录。
  3. 运行以下命令:
sh 复制代码
go run client.go

你应该会看到客户端向服务器发送请求,并接收并打印服务器返回的用户信息。

通过以上步骤,你将了解如何使用 Protobuf 定义数据结构,并通过 gRPC 实现一个简单的客户端-服务器应用程序。

例子 2:序列化

example.com/your_project/proto 新建 example.go:

go 复制代码
syntax = "proto3";

package example;

option go_package = "./proto";

// 定义一个简单的消息类型
message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
}

example.com/your_project/ 下运行

sh 复制代码
protoc --go_out=. --go-grpc_out=. proto/example.proto

example.com/your_project/ 新建 main.go

go 复制代码
package main

import (
	"fmt"
	"log"

	pb "github.com/chengxuyuanermao/test/proto"
	"google.golang.org/protobuf/proto"
)

func main() {
	// 创建一个新的 Person 消息
	p := &pb.Person{
		Name:  "John Doe",
		Id:    1234,
		Email: "johndoe@example.com",
	}

	// 序列化消息到二进制格式
	data, err := proto.Marshal(p)
	if err != nil {
		log.Fatalf("Marshaling error: %v", err)
	}

	// 打印序列化的二进制数据
	fmt.Printf("Serialized data: %x\n", data)

	// 反序列化二进制数据到消息
	newPerson := &pb.Person{}
	err = proto.Unmarshal(data, newPerson)
	if err != nil {
		log.Fatalf("Unmarshaling error: %v", err)
	}

	// 打印反序列化的消息
	fmt.Printf("Unmarshaled data: %v\n", newPerson)
}

运行 main.go:

sh 复制代码
Serialized data: 0a084a6f686e20446f6510d2091a136a6f686e646f65406578616d706c652e636f6d
Unmarshaled data: name:"John Doe" id:1234 email:"johndoe@example.com"
相关推荐
毕设源码-邱学长3 分钟前
【开题答辩全过程】以 基于SpringBoot的理工学院学术档案管理系统为例,包含答辩的问题和答案
java·spring boot·后端
修己xj12 分钟前
SpringBoot解析.mdb文件实战指南
java·spring boot·后端
lpfasd12330 分钟前
Spring Boot 定时任务详解(从入门到实战)
spring boot·后端·python
moxiaoran575334 分钟前
Go语言的文件操作
开发语言·后端·golang
赴前尘1 小时前
记一次golang进程执行卡住的问题排查
开发语言·后端·golang
码农小卡拉1 小时前
Prometheus 监控 SpringBoot 应用完整教程
spring boot·后端·grafana·prometheus
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue球鞋购物系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
苏渡苇2 小时前
用 Spring Boot 项目给工厂装“遥控器”:一行 API 控制现场设备!
java·人工智能·spring boot·后端·网络协议·边缘计算
短剑重铸之日2 小时前
《设计模式》第五篇:策略模式
java·后端·设计模式·策略模式
步步为营DotNet3 小时前
深入理解ASP.NET Core Middleware:管道执行机制与高效应用
后端·asp.net