Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Serialization 如何反序列化非标准大小字段?_Serialization_Go_Binary_Bit Fields - Fatal编程技术网

Serialization 如何反序列化非标准大小字段?

Serialization 如何反序列化非标准大小字段?,serialization,go,binary,bit-fields,Serialization,Go,Binary,Bit Fields,我必须反序列化来自另一个应用程序的一些二进制消息。我很想使用,但消息结构中的某些字段使用“非标准”位数(5位、3位、…10位…) 有没有办法处理这种类型的结构?我已经寻找了一段时间没有任何成功,所以任何帮助将是非常欢迎的 提前谢谢 我将试着举个例子来澄清我的问题。鉴于代码: package main import ( "encoding/binary" "fmt" restruct "gopkg.in/restruct.v1" ) type MessageType

我必须反序列化来自另一个应用程序的一些二进制消息。我很想使用,但消息结构中的某些字段使用“非标准”位数(5位、3位、…10位…)

有没有办法处理这种类型的结构?我已经寻找了一段时间没有任何成功,所以任何帮助将是非常欢迎的

提前谢谢

我将试着举个例子来澄清我的问题。鉴于代码:

package main

import (
    "encoding/binary"
    "fmt"

    restruct "gopkg.in/restruct.v1"
)

type MessageType uint8

const (
    MessageTypeOne MessageType = iota + 1
    MessageTypeTwo
    MessageTypeThree
)

// Message is the data to deserialize from the binary stream
type Message struct {
    Length     uint32      `struct:"uint32"` // message size in bytes (including length)
    Type       MessageType `struct:"uint8"`
    Version    uint8       `struct:"uint8:4"` // Just need 4 bits
    Subversion uint8       `struct:"uint8:2"` // just need 2 bits
    Optional   uint8       `struct:"uint8:1"` // just one bit --> '1' means next field is NOT present
    NodeName   string      ``
    ANumber    uint16      `struct:"uint16:10"` // just need 10 bits
}

// (length(4)+type(1)+(version(4bits)+Subversion(2bits)+Optional(1bit))) = 6 bytes
// need 32bit alignment
func main() {
    var inStream = []byte{0x08, // just 8 bytes needed
        0x01,       // messge type = MessageTypeOne
        0x4a,       // Version=0100 Subversion=10 Optional=1 ANumber = 0 (MSB bit)
        0x00, 0x60, // ANumber(000 0000 011) Padding = 0 0000 for 32 bits alignment
    }
    var msg Message

    err := restruct.Unpack(inStream, binary.BigEndian, &msg)
    if err != nil {
        panic(err)
    }
    fmt.Println(msg)
    // Expected:
    // msg.Length = 8
    // msg.Type = 1
    // msg.Version = 4
    // msg.Subversion = 2
    // msg.Optional = 1
    // msg.NodeName = ""
    // msg.ANumber = 3
}
我将从TCP连接接收inStream,并希望对二进制数据进行反序列化,并获得具有预期值的消息结构

希望这能澄清我的问题


再次感谢;)

虽然可能没有通用包来实现这种自定义结构打包,但您可以轻松创建自己的方法,只提取每个字段所需的位

func (m *Message) UnmarshalBinary(data []byte) error {
    m.Length = binary.BigEndian.Uint32(data[:4])

    if int(m.Length) > len(data) {
        return fmt.Errorf("not enough bytes")
    }

    m.Type = MessageType(data[4])

    m.Version = data[5] >> 4
    m.Subversion = data[5] >> 2 & 0x03
    m.Optional = data[5] >> 1 & 0x01

    // move the index for ANumber back if there's an optional string
    idx := 6
    if m.Optional == 0 {
        // remove the last two bytes for ANumber
        end := int(m.Length) - 2
        m.NodeName = string(data[6:end])
        idx = end
    }

    m.ANumber = uint16(data[idx]&0xc0)<<2 | uint16(data[idx]&0x3f<<2|data[idx+1]>>6)
    return nil
func(m*消息)解组二进制(数据[]字节)错误{
m、 长度=binary.BigEndian.Uint32(数据[:4])
如果int(m.Length)>len(数据){
返回fmt.Errorf(“字节不足”)
}
m、 Type=MessageType(数据[4])
m、 版本=数据[5]>>4
m、 Subversion=data[5]>>2&0x03
m、 可选=数据[5]>>1&0x01
//如果有可选字符串,请将一个成员的索引向后移动
idx:=6
如果m.可选==0{
//删除一个成员的最后两个字节
结束:=int(m.长度)-2
m、 NodeName=string(数据[6:end])
idx=结束
}

m、 ANumber=uint16(data[idx]&0xc0)我一直在为struct.io开发一些补丁,以便能够使用位字段…仍然没有完全测试,但似乎可以工作

测试后将尝试发送拉取请求

func (e *encoder) writeBits(f field, inBuf []byte) {

    var inputLength uint8 = uint8(len(inBuf))

    if f.BitSize == 0 {
        // Having problems with complex64 type ... so we asume we want to read all
        //f.BitSize = uint8(f.Type.Bits())
        f.BitSize = 8 * inputLength
    }

    // destPos: Destination position ( in the result ) of the first bit in the first byte
    var destPos uint8 = 8 - e.bitCounter

    // originPos: Original position of the first bit in the first byte
    var originPos uint8 = f.BitSize % 8
    if originPos == 0 {
        originPos = 8
    }

    // numBytes: number of complete bytes to hold the result
    var numBytes uint8 = f.BitSize / 8

    // numBits: number of remaining bits in the first non-complete byte of the result
    var numBits uint8 = f.BitSize % 8

    // number of positions we have to shift the bytes to get the result
    var shift uint8
    if originPos > destPos {
        shift = originPos - destPos
    } else {
        shift = destPos - originPos
    }
    shift = shift % 8

    var inputInitialIdx uint8 = inputLength - numBytes
    if numBits > 0 {
        inputInitialIdx = inputInitialIdx - 1
    }

    if originPos < destPos {
        // shift left
        carry := func(idx uint8) uint8 {
            if (idx + 1) < inputLength {
                return (inBuf[idx+1] >> (8 - shift))
            }
            return 0x00

        }
        mask := func(idx uint8) uint8 {
            if idx == 0 {
                return (0x01 << destPos) - 1
            }
            return 0xFF
        }
        var idx uint8 = 0
        for inIdx := inputInitialIdx; inIdx < inputLength; inIdx++ {
            e.buf[idx] |= ((inBuf[inIdx] << shift) | carry(inIdx)) & mask(idx)
            idx++
        }

    } else {
        // originPos >= destPos => shift right
        var idx uint8 = 0
        // carry : is a little bit tricky in this case because of the first case
        // when idx == 0 and there is no carry at all
        carry := func(idx uint8) uint8 {
            if idx == 0 {
                return 0x00
            }
            return (inBuf[idx-1] << (8 - shift))
        }
        mask := func(idx uint8) uint8 {
            if idx == 0 {
                return (0x01 << destPos) - 1
            }
            return 0xFF
        }
        inIdx := inputInitialIdx
        for ; inIdx < inputLength; inIdx++ {
            //note: Should the mask be done BEFORE the OR with carry?
            e.buf[idx] |= ((inBuf[inIdx] >> shift) | carry(inIdx)) & mask(idx)

            idx++
        }
        if ((e.bitCounter + f.BitSize) % 8) > 0 {
            e.buf[idx] |= carry(inIdx)
        }
    }

    //now we should update buffer and bitCounter
    e.bitCounter = (e.bitCounter + f.BitSize) % 8

    // move the head to the next non-complete byte used
    headerUpdate := func() uint8 {
        if (e.bitCounter == 0) && ((f.BitSize % 8) != 0) {
            return (numBytes + 1)
        }
        return numBytes
    }

    e.buf = e.buf[headerUpdate():]

    return
}
func(e*编码器)写入位(f字段,inBuf[]字节){
变量输入长度uint8=uint8(len(inBuf))
如果f.BitSize==0{
//complex64类型有问题…所以我们想全部阅读
//f、 BitSize=uint8(f.Type.Bits())
f、 位大小=8*inputLength
}
//destPos:第一字节中第一位的目标位置(结果中)
var destPos uint8=8-e.位计数器
//originPos:第一个字节中第一位的原始位置
var originPos uint8=f.位大小%8
如果originPos==0{
originPos=8
}
//numBytes:保存结果的完整字节数
var numBytes uint8=f.BitSize/8
//numBits:结果的第一个非完整字节中剩余的位数
var numBits uint8=f.位大小%8
//我们必须移动字节才能得到结果的位置数
var移位uint8
如果originPos>destPos{
shift=原始位置-目标位置
}否则{
shift=destPos-originPos
}
班次=班次%8
变量inputInitialIdx uint8=输入长度-单位
如果大于0{
inputInitialIdx=inputInitialIdx-1
}
如果originPos>(8班次))
}
返回0x00
}
掩码:=func(idx uint8)uint8{
如果idx==0{
返回(0x01右移)
变量idx uint8=0
//carry:由于第一种情况,在这种情况下有点棘手
//当idx==0且根本没有进位时
进位:=函数(idx uint8)uint8{
如果idx==0{
返回0x00
}
返回(inBuf[idx-1]移位)|进位(inIdx))&掩码(idx)
idx++
}
如果((e.bitCounter+f.BitSize)%8)>0{
e、 buf[idx]|=进位(inIdx)
}
}
//现在我们应该更新缓冲区和位计数器
e、 位计数器=(e.bitCounter+f.BitSize)%8
//将磁头移动到使用的下一个非完整字节
headerUpdate:=func()uint8{
如果(e.bitCounter==0)和((f.BitSize%8)!=0){
返回值(字节数+1)
}
返回单位
}
e、 buf=e.buf[headerUpdate():]
返回
}

当然有办法处理,但如果您需要帮助,我们需要知道格式是什么。请提供一个示例,说明您要做什么。感谢您的回答……代码很好,它为我现在的做法设置了路径。