Skip to content
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

link程序 , 复杂包头, 如何进行拆包? #35

Closed
gyf19 opened this issue Jul 2, 2015 · 9 comments
Closed

link程序 , 复杂包头, 如何进行拆包? #35

gyf19 opened this issue Jul 2, 2015 · 9 comments

Comments

@gyf19
Copy link

gyf19 commented Jul 2, 2015

例如包头:

typedef struct _yar_header {
    unsigned int   id;            // transaction id
    unsigned short version;       // protocl version
    unsigned int   magic_num;     // default is: 0x80DFEC60
    unsigned int   reserved;
    unsigned char  provider[32];  // reqeust from who
    unsigned char  token[32];     // request token, used for authentication
    unsigned int   body_len;      // request body len
}
@bg5sbk
Copy link
Contributor

bg5sbk commented Jul 3, 2015

你好。

如果用funny/binary包当中的binary.Reader和binary.Writer的分包机制,只能做简单的消息分包,无法提取包头信息。

所以,对于你说的这种需要提取包头信息的情况,应该自己实现一个link.Codec来做消息解析。

@gyf19
Copy link
Author

gyf19 commented Jul 3, 2015

你好,达达
这种包头信息,很常见吧。link 不打算支持一下? 哈哈
最近好像有大量代码修改 ,link 稳定了吗?

@bg5sbk
Copy link
Contributor

bg5sbk commented Jul 3, 2015

包头和包体内容同时提取的确是一些协议设计中会出现,但是协议太过具体,没办法放到link里面。

link能提供的只有机制,Codec机制足够抽象,所以可以用来实现这样类型的协议,实施起来应该不复杂。

我这里友情赠送演示代码一份,请针对具体需求再自行改造:

package link

import (
    "github.com/funny/binary"
    "io"
)

type YarMessage struct {
    Id       uint32
    Version  uint16
    MagicNum uint32
    Provider [32]byte
    Token    [32]byte
    Message  interface{}
}

type YarCodecType struct {
    CodecType CodecType
}

func Yar(codecType CodecType) YarCodecType {
    return YarCodecType{codecType}
}

func (codecType YarCodecType) NewCodec(r io.Reader, w io.Writer) Codec {
    br := binary.NewReader(r)
    bw := binary.NewWriter(w)
    pr := binary.NewPacketReader(binary.SplitByUint32BE, br)
    pw := binary.NewPacketWriter(binary.SplitByUint32BE, bw)
    return &YarCodec{
        codec:   codecType.CodecType.NewCodec(pr, pw),
        reader:  br,
        writer:  bw,
        pwriter: pw,
    }
}

type YarCodec struct {
    codec   Codec
    reader  *binary.Reader
    writer  *binary.Writer
    pwriter *binary.PacketWriter
}

func (codec *YarCodec) Decode(msg interface{}) error {
    ym := msg.(*YarMessage)

    ym.Id = codec.reader.ReadUint32BE()
    ym.Version = codec.reader.ReadUint16BE()
    ym.MagicNum = codec.reader.ReadUint32BE()
    _ = codec.reader.ReadUint32BE()
    codec.reader.ReadFull(ym.Provider[:])
    codec.reader.ReadFull(ym.Token[:])

    return codec.codec.Decode(ym.Message)
}

func (codec *YarCodec) Encode(msg interface{}) error {
    ym := msg.(*YarMessage)

    codec.writer.WriteUint32BE(ym.Id)
    codec.writer.WriteUint16BE(ym.Version)
    codec.writer.WriteUint32BE(ym.MagicNum)
    codec.writer.WriteUint32BE(0)
    codec.writer.Write(ym.Provider[:])
    codec.writer.Write(ym.Token[:])

    if err := codec.codec.Encode(ym.Message); err != nil {
        return err
    }
    return codec.pwriter.Flush()
}

已通过单元测试:

func Test_Yar(t *testing.T) {
    SessionTest(t, Bufio(Yar(Json())), func(t *testing.T, session *Session) {
        for i := 0; i < 2000; i++ {
            msg1 := RandObject()
            msg2 := &YarMessage{Message: &msg1}
            copy(msg2.Provider[:], RandBytes(32))
            copy(msg2.Token[:], RandBytes(32))
            err := session.Send(msg2)
            unitest.NotError(t, err)

            var msg3 TestObject
            msg4 := &YarMessage{Message: &msg3}
            err = session.Receive(msg4)
            unitest.NotError(t, err)
            unitest.Pass(t, msg2.Provider == msg4.Provider)
            unitest.Pass(t, msg2.Token == msg4.Token)
            unitest.Pass(t, msg1 == msg3)
        }
    })
}

前后差不多花了半个多小时,开发起来还算是比较高效的。

@LaoZhongGu
Copy link

解包还需要考虑粘包的情况吧?这个应该自己逻辑处理就可以了,提供机制就好了,类似Netty那样。

@bg5sbk
Copy link
Contributor

bg5sbk commented Jul 3, 2015

@LaoZhongGu 上面的代码已经包含了消息分包逻辑在里面

@gyf19
Copy link
Author

gyf19 commented Jul 3, 2015

谢谢 达达大神。 清楚每个项目包头都不一样。
我可能表达不很清楚, 我的意思是 需要有一个类似例子,可以让我这样的小白来借鉴。

@gyf19 gyf19 closed this as completed Aug 11, 2015
@hz602
Copy link

hz602 commented Aug 18, 2015

Codec 删除了吗?

@bg5sbk
Copy link
Contributor

bg5sbk commented Aug 31, 2015

没删,看api.go里面的接口声明,有些变动

@ericx10ng
Copy link

达达大神, 网络收包的粘包问题有没有提供机制处理?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants