Comments (7)
大家好,我做了Protobuf的实验,基本上比较OK,具体应用到实际项目中可能需要再根据项目需求调整(比如根据包头来得知消息类型?)。
我用的库是这个:https://github.com/golang/protobuf
之前我没用过Protobuf,所以一开始花了点时间搭建环境,在Mac上搭建起来还是比较顺利的,就是要装上原始的Protobuf命令行工具,然后装上生成Go代码的Protobuf工具插件,插件必须让Protobuf工具可以搜索到,所以我把插件所在目录添加到PATH环境变量里。
然后就是按Protobuf项目给的Go示例代码,生成了一份test.pb.go
代码出来,然后实现Protobuf的Codec。
因为Protobuf好像无法像Xml、Json、Gob这三个编码格式一样采用流编码和流解码,所以在Encoder和Decoder构造函数中必须强制要求外部传进来的是binary.PacketReader
和binary.PacketWriter
,也就是说这个ProtobufCodec
必须配合link.Packet()
使用。(也可能是我对Protobuf的接口不熟悉,没找到流式编解码接口)
link的Codec实现是很灵活的,如果觉得一个个Codec套起来使用很烦,也可以直接就实现一个内置分包格式的项目专用Codec,这边只是一个简单示例,就不把各种可能性都列举一遍了。
下面是完整测试代码:
package main
import (
"io"
"sync"
"github.com/funny/binary"
"github.com/funny/link"
"github.com/golang/protobuf/proto"
)
func main() {
serverInitWait.Add(1)
serverStopWait.Add(1)
go server()
go client()
serverStopWait.Wait()
}
var (
serverAddr string
serverInitWait sync.WaitGroup
serverStopWait sync.WaitGroup
)
func server() {
server, err := link.Serve("tcp", "0.0.0.0:0", link.Packet(link.Uint16BE, ProtobufCodec{}))
if err != nil {
panic(err)
}
serverAddr = server.Listener().Addr().String()
serverInitWait.Done()
session, err := server.Accept()
if err != nil {
panic(err)
}
newTest := &Test{}
err = session.Receive(newTest)
if err != nil {
panic(err)
}
if newTest.GetLabel() != "hello" {
println("data mismatch %q != 'hello'")
} else {
println("done")
}
session.Close()
server.Stop()
serverStopWait.Done()
}
func client() {
serverInitWait.Wait()
client, err := link.Connect("tcp", serverAddr, link.Packet(link.Uint16BE, ProtobufCodec{}))
if err != nil {
panic(err)
}
err = client.Send(&Test{
Label: proto.String("hello"),
Type: proto.Int32(17),
Optionalgroup: &Test_OptionalGroup{
RequiredField: proto.String("good bye"),
},
})
if err != nil {
panic(err)
}
client.Close()
}
type ProtobufCodec struct {
}
func (_ ProtobufCodec) NewEncoder(w io.Writer) link.Encoder {
return ProtobufEncoder{
writer: w.(*binary.PacketWriter),
}
}
func (_ ProtobufCodec) NewDecoder(r io.Reader) link.Decoder {
return ProtobufDecoder{
reader: r.(*binary.PacketReader),
}
}
type ProtobufEncoder struct {
writer io.Writer
}
func (pe ProtobufEncoder) Encode(msg interface{}) error {
data, err := proto.Marshal(msg.(proto.Message))
if err != nil {
return err
}
_, err = pe.writer.Write(data)
return err
}
type ProtobufDecoder struct {
reader *binary.PacketReader
}
func (pe ProtobufDecoder) Decode(msg interface{}) error {
data, err := pe.reader.ReadPacket()
if err != nil {
return err
}
return proto.Unmarshal(data, msg.(proto.Message))
}
这里一起给出test.pb.go
的代码,方便大家实验:
// Code generated by protoc-gen-go.
// source: test.proto
// DO NOT EDIT!
/*
Package example is a generated protocol buffer package.
It is generated from these files:
test.proto
It has these top-level messages:
Test
*/
package main
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type FOO int32
const (
FOO_X FOO = 17
)
var FOO_name = map[int32]string{
17: "X",
}
var FOO_value = map[string]int32{
"X": 17,
}
func (x FOO) Enum() *FOO {
p := new(FOO)
*p = x
return p
}
func (x FOO) String() string {
return proto.EnumName(FOO_name, int32(x))
}
func (x *FOO) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
if err != nil {
return err
}
*x = FOO(value)
return nil
}
type Test struct {
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Test) Reset() { *m = Test{} }
func (m *Test) String() string { return proto.CompactTextString(m) }
func (*Test) ProtoMessage() {}
const Default_Test_Type int32 = 77
func (m *Test) GetLabel() string {
if m != nil && m.Label != nil {
return *m.Label
}
return ""
}
func (m *Test) GetType() int32 {
if m != nil && m.Type != nil {
return *m.Type
}
return Default_Test_Type
}
func (m *Test) GetReps() []int64 {
if m != nil {
return m.Reps
}
return nil
}
func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
if m != nil {
return m.Optionalgroup
}
return nil
}
type Test_OptionalGroup struct {
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
func (*Test_OptionalGroup) ProtoMessage() {}
func (m *Test_OptionalGroup) GetRequiredField() string {
if m != nil && m.RequiredField != nil {
return *m.RequiredField
}
return ""
}
func init() {
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
}
因为代码是两份,所以要用 go run main.go test.pb.go
这样的形式来运行测试代码。
from link.
可以的,跟序列化格式无关,跟分包协议也无关,参考已有的几个codec或利用已有的codec实现protobuf编解码器就可以了
from link.
@idada 达神有空可以实现一下:) 或者开一个目录等pr :)
from link.
.....这个自己实现不就好了。这么简单
from link.
赞达神 代码合到主线里吗
from link.
作为个例子来举例就行了,不要做大而全的东西。按需定制就可以了。
from link.
@oikomi 不适合放入项目里的,只是演示的代码,实际项目里用Protobuf应该要做更多事情的,比如上面说的消息类型识别,不同项目会很不一样。
from link.
Related Issues (20)
- 请教解码 HOT 2
- session完全与net.Conn脱离关系了,应该继承net.Conn的 HOT 1
- 关于udp的实现 HOT 1
- tcp连接写,是否有必要加锁 HOT 1
- 为啥没有session start的callback? HOT 1
- tcp长链接,一个connection一个goroutine会不会太暴力 HOT 2
- 关于session的close HOT 1
- 问题 HOT 2
- readme文档示例代码没更新
- 当收到一个不合法的数据时,服务器就crash掉了 HOT 2
- Does this version have a benchmark performance test?
- Codec接口为什么要实现Send和Recive呢? HOT 2
- server 端出现疯狂 EOF错误
- Link
- Bitcoin wallet
- 如何获取对端地址 HOT 1
- 觉得项目不错,如果托管出去是不是会让这个项目更活跃。 HOT 2
- goroutine 21498 [IO wait] HOT 1
- net Temporary()函数已被弃用
- Hi HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from link.