用 golang 写了一个字节数据的编解码, 可以简化编写 tcp 服务时, 消息的封装和解析 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Guidance3204
V2EX    Go 编程语言
  •  
  •   Guidance3204 2021-08-23 14:24:00 +08:00 2683 次点击
    这是一个创建于 1519 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://github.com/lai323/bytecodec

    这个库实现 []bytestruct 编解码, 对于要处理特别多结构不同的字节消息

    使用这个就不用每种消息类型都去写编解码了

    可以向处理 json 一样处理字节数据

    package main import ( "fmt" "time" "github.com/lai323/bytecodec" ) type Header struct { SerialNo uint16 Time int64 } type Packet struct { Header Header Phone string `bytecodec:"length:11"` // 使用长度固定为 11 的字符串 MsgLength uint8 `bytecodec:"lengthref:Msg"` // 表示这个字段的值是 Msg 的字节长度 Msg string `bytecodec:"gbk"` // 使用 GBK 编码 } func main() { p := Packet{ Header: Header{ SerialNo: 1, Time: time.Now().Unix(), }, Phone: "18102169375", Msg: "你好", } b, err := bytecodec.Marshal(p) fmt.Println(fmt.Sprintf("%#v", b), err) out := &Packet{} err = bytecodec.Unmarshal(b, out) fmt.Println(fmt.Sprintf("%#v", out), err) } 
    11 条回复    2021-08-25 10:32:22 +08:00
    lesismal
        1
    lesismal  
       2021-08-23 16:00:04 +08:00   1
    关于序列化,protobuf/json 足够用了,并且还有其他一大堆知名的序列化方案可选。

    另外,是否支持完备的嵌套,比如是否支持 struct 内的 struct 成员、数组成员、数组成员的元素是 struct 等。如果支持,算是相对完善,剩下的要看性能,如果不支持,对业务太不友好了。对于性能,主要是两个方面考量,一是速度,二是生成的数据长度。因为是用注释的方式,也就意味着要反射,性能可能不会比 protobuf 这些生成代码的快、长度也不会比 protobuf 能省,因为没有按照固定的 proto 生成固定的代码,所以传输给对方解码时仍需要带上 key 信息,相比 json 倒是可以把一些引号冒号省了,但可能又跟 MessagePack 差不多了。

    单就序列化,对简化 tcp 服务消息封装和解析帮助不大。楼主应该是指这个 Header 做包长相关的流到包的解析。这个对于 go 也比较简单,单独协程读的方案,有 ReadFull 这些方便的方法,不需要像 c/c++ 那些异步解析稍微费神(但是异步解析费神也不算太多)。所以,整体看,tcp 服务也没必要用这种序列化方案。实现这种序列化,对学习和提高编解码能力是好事情,但建议使用更成熟优秀的方案。
    Guidance3204
        2
    Guidance3204  
    OP
       2021-08-23 16:51:54 +08:00
    @lesismal 感谢指教,这个库的目的不是要发明一种速度快、体积小序列化方式,主要是处理字节流到对象具体属性的映射,比如车载终端或 POS 机里面一些基于 TCP 通信标准,这些标准会定义比较多的消息类型,每种消息结构不一样,我需要针对不同消息写一个编解码,这里面有非常多的重复工作,例如:读取一个 byte,读取一个固定长度的字符串,先读一个长度,再按长度读一个字节数组,这个库是为了处理这些重复工作

    这个库支持对象的嵌套,因为要解析未知 struct 使用了反射,tag 只是做一下辅助,数据转换主要还是看字段数据类型
    index90
        3
    index90  
       2021-08-23 17:17:48 +08:00
    gob,pb 不香么?
    MoYi123
        4
    MoYi123  
       2021-08-23 17:34:16 +08:00
    我在上家公司为了对接之前的老项目,也写过类似的代码. 应该还是有应用场景的.
    xhelin
        5
    xhelin  
       2021-08-23 18:00:35 +08:00
    @marceliu323 所以你这个库的适用场景是:传输协议已经长成那样了,然后需要从流中解析出对象来。
    janxin
        6
    janxin  
       2021-08-23 18:19:51 +08:00
    很多人没用过二进制协议所以不是很清楚吧,你这个 benchmark 做了没
    lesismal
        7
    lesismal  
       2021-08-23 18:33:45 +08:00
    @marceliu323 嗯嗯,如果是 pos 机里面已经使用了某种序列化,那是没法换 pb 之类的了,如果 c/s 端都是自家可控的,可以选择 pb 之类的。

    一些老 c/cpp 项目是直接把不涉及深拷贝的 struct 的 sizeof 内存段拷贝过来用于序列化的,另一端 c/cpp 也是直接 struct X *p = (struct X *)buf,这种确实比较酸爽。唯有重构,能得结果 :joy:
    rix
        8
    rix  
       2021-08-25 06:46:36 +08:00   1
    更多的候二制的序列化是有的,比如有 if else 和循的,甚至可以是完的。很都用 tag 的明定,其最好的方式是每一 Encode 和 Decode 函解,或者一 SDL 出需要的 Encode 和 Decode 函。可以看看 https://kaitai.io/
    Guidance3204
        9
    Guidance3204  
    OP
       2021-08-25 09:53:33 +08:00
    @rix 很棒的工具
    Guidance3204
        10
    Guidance3204  
    OP
       2021-08-25 09:57:19 +08:00
    @janxin 只做了功能性测试,性能方面只对 struct 的字段做了一下缓存,不至于每次都解析 stuct,性能应该不会太好,估计和 json 标准库差不多
    KickAssTonight
        11
    KickAssTonight  
       2021-08-25 10:32:22 +08:00
    从例子中看,使用起来挺简单的。
    感觉这个库是个对二进制数据封包和拆包的 helper 。如果是个 packer 的话,第一感觉是应当实现 pack() / unpack() 方法,而不是 marshal / unmarshal, 后者更像是对数据的编码,属于 codec,例如 json / protobuf 。
    封包拆包可以看下这两个库 https://github.com/smallnest/goframehttps://github.com/zhuangsirui/binpacker
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1656 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 16:23 PVG 00:23 LAX 09:23 JFK 12:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86