-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
请问可以和protobuf结合使用吗? #37
Comments
可以的,跟序列化格式无关,跟分包协议也无关,参考已有的几个codec或利用已有的codec实现protobuf编解码器就可以了 |
@idada 达神有空可以实现一下:) 或者开一个目录等pr :) |
.....这个自己实现不就好了。这么简单 |
大家好,我做了Protobuf的实验,基本上比较OK,具体应用到实际项目中可能需要再根据项目需求调整(比如根据包头来得知消息类型?)。 我用的库是这个:https://github.com/golang/protobuf 之前我没用过Protobuf,所以一开始花了点时间搭建环境,在Mac上搭建起来还是比较顺利的,就是要装上原始的Protobuf命令行工具,然后装上生成Go代码的Protobuf工具插件,插件必须让Protobuf工具可以搜索到,所以我把插件所在目录添加到PATH环境变量里。 然后就是按Protobuf项目给的Go示例代码,生成了一份 因为Protobuf好像无法像Xml、Json、Gob这三个编码格式一样采用流编码和流解码,所以在Encoder和Decoder构造函数中必须强制要求外部传进来的是 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))
} 这里一起给出 // 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)
} 因为代码是两份,所以要用 |
赞达神 代码合到主线里吗 |
作为个例子来举例就行了,不要做大而全的东西。按需定制就可以了。 |
@oikomi 不适合放入项目里的,只是演示的代码,实际项目里用Protobuf应该要做更多事情的,比如上面说的消息类型识别,不同项目会很不一样。 |
No description provided.
The text was updated successfully, but these errors were encountered: