Protobuf 是 Protocol Buffers 的简称,是一种与语言、平台无关,可扩展的序列化结构化数据的数据描述语言,Protobuf作为接口规范的描述语言,可以作为设计安全的跨语言PRC接口的基础工具。
hello.proto 文件
syntax = "proto3";
package main;
message String {
string value = 1;
}
消息体中字段定义了唯一的数字值。这些数字是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。
最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999]的标识号, Protobuf 协议实现中对这些进行了预留。如果非要在 .proto 文件中使用这些预留标识号,编译时就会报警。类似地,你不能使用之前保留的任何标识符。
.proto 文件添加注释,可以使用C/C++风格的 // 和 /* … */ 语法格式
如果从前面定义的消息中删除了 和 字段,应保留其字段编号,使用关键字 reserved
:
syntax "proto3";
message Stock {
reserved 3, 4;
// ...
}
还可以将 reserved 关键字用作将来可能添加的字段的占位符。可以使用 to
关键字将连续字段号占位。
syntax "proto3";
message Info {
reserved 2, 9 to 11, 15;
// ...
}
Protobuf 核心的工具集是 C++ 语言开发的,官方的 protoc 编译器中并不支持Go语言。要想基于上面 的 hello.proto 文件生成相应的Go代码,需要安装相应的插件。
通过以下命令生成相应的Go代码:
$ protoc --go_out=. hello.proto
protobuf 所生成出来的数据类型并非与原始的类型完全一致,下面是一些常见的类型映射:
pb.go 文件是对 proto 文件所生成的对应的 Go 代码,在实际应用中将会引用到此文件。
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hello.proto
package main
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type String struct {
Value *String `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *String) Reset() { *m = String{} }
func (m *String) String() string { return proto.CompactTextString(m) }
func (*String) ProtoMessage() {}
func (*String) Descriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{0}
}
func (m *String) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_String.Unmarshal(m, b)
}
func (m *String) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_String.Marshal(b, m, deterministic)
}
func (m *String) XXX_Merge(src proto.Message) {
xxx_messageInfo_String.Merge(m, src)
}
func (m *String) XXX_Size() int {
return xxx_messageInfo_String.Size(m)
}
func (m *String) XXX_DiscardUnknown() {
xxx_messageInfo_String.DiscardUnknown(m)
}
var xxx_messageInfo_String proto.InternalMessageInfo
func (m *String) GetValue() *String {
if m != nil {
return m.Value
}
return nil
}
func init() {
proto.RegisterType((*String)(nil), "main.String")
}
func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) }
var fileDescriptor_61ef911816e0a8ce = []byte{
// 84 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9,
0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xc9, 0x4d, 0xcc, 0xcc, 0x53, 0xd2, 0xe1,
0x62, 0x0b, 0x2e, 0x29, 0xca, 0xcc, 0x4b, 0x17, 0x52, 0xe2, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d,
0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x36, 0xe2, 0xd1, 0x03, 0xc9, 0xeb, 0x41, 0x24, 0x83, 0x20,
0x52, 0x49, 0x6c, 0x60, 0xad, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0x0c, 0x0e, 0x54,
0x49, 0x00, 0x00, 0x00,
}
基于 String 类型,重新实现 HelloService 服务
package main
import (
"log"
"net"
"net/rpc"
"rpc/protoc"
)
// HelloService is rpc server obj
type HelloService struct{}
//Hello方法的输入参数和输出的参数均改用 Protobuf 定义的 String 类型表示。
//因为新的输入参数为结构体类型,因此改用指针类型作为输入参数,函数的内部代码同时也做了相应的调整。
func (p *HelloService) Hello(request *protoc.String, reply *protoc.String) error {
reply.Value = "hello:" + request.GetValue()
return nil
}
func main() {
rpc.RegisterName("HelloService", new(HelloService))
listener, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal("ListenTCP error:", err)
}
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error", err)
}
rpc.ServeConn(conn)
}
下面是客户端请求HelloService服务的代码 client.go:
package main
import (
"fmt"
"log"
"net/rpc"
"rpc/protoc"
)
func main() {
client, err := rpc.Dial("tcp", "localhost:1234")
if err != nil {
log.Fatal("dialing err:", err)
}
var reply = &protoc.String{}
var param = &protoc.String{
Value: "hello wekenw",
}
err = client.Call("HelloService.Hello", ¶m, &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
}
开启服务器端,开启客户端。客户端的执行结果如下:
$ go run client.go
value:"hello:hello wekenw"
图片及部分相关技术知识点来源于网络搜索,侵权删!
参考资料:
https://blog.csdn.net/qq_22660775/article/details/89163881
https://docs.microsoft.com/zh-cn/dotnet/architecture/grpc-for-wcf-developers/protobuf-reserved
https://golang2.eddycjy.com/posts/ch3/01-simple-grpc-protobuf/
《Go语言高级编程》
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有