正确的习惯用法字节缓冲区的读写

huangapple go评论72阅读模式
英文:

correct idiomatic byte buffer reading and writing

问题

你需要读取一个结构化协议的数据,其中包含消息长度、类型和值。你想知道在Go语言中如何实现这个功能,但是在io、bufio和encoding等包中找不到合适的方法和示例。你还需要组装一个回复,类似于WriteInt32、WriteString和WriteByte。你想将Python代码转换为Go代码,Python代码中使用了struct.unpack和pack函数。

英文:

I have a net/socket open. I need to read a structured protocol off the wire. Ie I have

messagelength|type|value|type|value ...

where messagelength is 4 bytes, type one byte, value depends on type,...

I am trying to work out the no-brainer way of doing this in go. I am swamped by io,bufio,encoding... I cant find the right place to start and cant find samples. Looking for ReadInt32, ReadByte,....

Next thing - i need to assemble a reply -> WriteInt32, WriteString, WriteByte,....

Trying to convert python to go, python code uses struct.unpack / pack

答案1

得分: 3

你可以使用包encoding/binary。你只需要用到Read()Write()这两个函数。下面是如何使用它们:

Read()函数的签名如下:

func Read(r io.Reader, order ByteOrder, data interface{}) error

这个函数从r按照ByteOrder的顺序读取数据到data中。data必须是一个指向固定大小值的指针(例如int32、字节或只包含固定大小成员的结构体)或者是这些值的切片。如果你传递一个指向结构体的指针,结构体字段将被无填充地读取,对于空白字段(即那些命名为_的字段)的数据将被读取并丢弃(适用于填充)。

针对你的具体问题,声明一个与数据流头部匹配的结构体。

type Header struct {
    Length uint32
    Type   uint8
}

读取一个数据包的头部(假设是大端序):

var hdr Header
if err = Read(connection, binary.BigEndian, &hdr); err != nil {
    // 处理读取错误
}

根据类型字节进行分支处理:

switch hdr.Type {
// 对于每种类型,读取到相应的特定类型的结构体中
// ...
}

Write()函数类似,但是用于写入数据而不是读取。

英文:

You can use the package encoding/binary. The only functions you will need are Read() and Write(). Here is how you use them:

The Read() function has the following signature:

func Read(r io.Reader, order ByteOrder, data interface{}) error

This function reads from r in order ByteOrder into data. data must be a pointer to a fixed-size value (e.g. an int32, a byte or a struct with only fixed size members) or a slice of such values. If you pass a pointer to a struct, struct fields are read in without padding, data corresponding for blank fields (i.e. those named _) is read and discarded (ideal for padding).

For your specific problem, declare a struct that matches the header of your data stream.

type Header struct {
    Length uint32
    Type   uint8
}

Consume the header of a packet (assume big endian):

var hdr Header
if err = Read(connection, binary.BigEndian, &hdr); err != nil {
    // deal with read error
}

Switch over the type byte:

switch hdr.Type {
// for each type, read into a type-specific struct
// ...
}

Write() is similar but writes instead of reading.

huangapple
  • 本文由 发表于 2014年5月21日 02:51:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/23767718.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定