V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Guidance3204
V2EX  ›  Go 编程语言

用 golang 写了一个字节数据的编解码, 可以简化编写 tcp 服务时, 消息的封装和解析

  •  
  •   Guidance3204 · 2021-08-23 14:24:00 +08:00 · 2113 次点击
    这是一个创建于 949 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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   ·   我们的愿景   ·   实用小工具   ·   5389 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 07:33 · PVG 15:33 · LAX 00:33 · JFK 03:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.