Golang中创建uint32时返回不完整的字节数组怎么办

Golang中创建uint32时返回不完整的字节数组怎么办 我尝试在一个数组中容纳两个地址和一个端口,然后,如代码所示,将其转换为 uint16 以便后续处理,但在输出中未能得到期望的结果。

s, d := net.IP{172, 16, 100, 11}, net.IP{10, 0, 88, 11}
var sp uint16 = 54876
//var dp uint16 = 445

var spByte = make([]byte, 2)
binary.BigEndian.PutUint16(spByte, sp)


var x = make([]byte, 10) // [172 16 100 11 10 0 88 11 214 92]
copy(x[:4], s)
copy(x[4:], d)
copy(x[8:], spByte)

ret := binary.BigEndian.Uint32(x)

var a, z uint16
a = uint16(ret >> 16)
z = uint16(ret & 0xFFFF)

newret := (uint32(a) << 16) | uint32(z)


var xs = make([]byte,10) // [172 16 100 11 0 0 0 0 0 0]
binary.BigEndian.PutUint32(xs,newret)

更多关于Golang中创建uint32时返回不完整的字节数组怎么办的实战教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

据我理解,实际上不可能将两个 uint16 数字转换为一个,然后再将其恢复为这两个数字?我只需要一个在 1-65535 范围内的数字。

更多关于Golang中创建uint32时返回不完整的字节数组怎么办的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是否有可能将三个字节压缩为两个字节?例如,将 [11 92 214] 这样的数组转换为 uint16?

@11132 你期望的输出是什么?如果你指的是切片末尾的0,那是因为你取了一个10字节的数组,只将前4个字节编码为uint32,然后“解包”了这4个字节。

我遇到了无法将16位整数移位16位的错误,因此我使用了uint32作为临时变量,并得到了这个结果:https://play.golang.org/p/cUrflqi37fV

我正在尝试将网络数据包中的源地址和目的地址的最后一个八位字节以及真实的目的端口保存在源端口(uint16)字段中,以便我可以在另一台设备上根据这些数据恢复路由。我可能可以使用目的端口作为辅助字段,因此实际上我有4字节的信息。我正在尝试编写一个算法,例如在数据包中传输路由。我曾尝试使用NATS来传输新连接出现时的信息,但这确实会减慢工作速度。我只是在寻找解决方案时感到困惑。

你无法将两个16位值(总共32位数据)存储到一个16位值中,然后再从中恢复出原始的32位数据,除非你使用了压缩。我认为,当你在处理单个的16位和32位值时,要实现这种级别的压缩是不可能的。但是,如果你有很多这样的值,并且将它们存储为32位整数,你可以使用像LZMA这样的算法来压缩它们,以利用比特位中可能存在的重复模式。

您无法使用任何传统的压缩算法(如霍夫曼编码、Lempel-Ziv(-Markov)等)以这种方式压缩单个字节。这些算法通常需要数百字节(通常是KiB、MiB)才能获得真正的空间节省(10-75%,具体取决于数据)。

如果您可以从值中完全丢弃某些位,那么您或许能够缩小这些值。例如,您是否只存储内网IPv4地址?如果是这样,您或许可以这样做:

与其实际存储完整的10.AAA.AAA.AAA、172.16.BBB.BBB或192.168.CCC.CCC地址,不如用2位来编码类别:

01 - A类 (10…) 10 - B类 (172.16…) 11 - C类

然后您分别只需要21、14和14位(对应A类、B类和C类)。

请注意,距离我上次必须思考IP地址、CIDR、子网掩码位等已经大约十年了,所以我可能在内网网络类别的细节上弄错,但我只是想说明,如果您不需要实际存储完整数据,您可以节省位数。

在所有这些之后,还有一个问题:为什么您试图将32位或24位数据存储到uint16中?

是的,我已经明白了这一点,我更进一步,现在只需要将两个 uint16 打包成一个,并以某种方式将其放回去。以下是我当前的代码:

    s, d  := net.IP{172, 16, 100, 11}, net.IP{10, 0, 88, 11}
var sp uint16 = 54876
//var dp uint16 = 445

var b, x = make([]byte,4),make([]byte,2)
binary.LittleEndian.PutUint16(x,sp)
n := copy(b,s[3:])
n += copy(b[n:],d[3:])
copy(b[n:],x)

ret := binary.LittleEndian.Uint32(b)

var a, z uint16
a = uint16(ret >> 16)
z = uint16(ret & 0xffff)

fmt.Printf("a = %d z = %d\n",a,z)

w := (z << 16) | a

fmt.Printf("Packing: %d\n", w)

a = w & 0xffff
z = (w >> 16 ) & 0xffff
fmt.Printf("a = %d z = %d\n",a,z)


newret := (uint32(a) << 16) | uint32(z)


var xs = make([]byte,4)
binary.LittleEndian.PutUint32(xs,newret)

你的问题在于对 binary.BigEndian.Uint32 的理解有误。Uint32 函数只读取切片的前4个字节,而你期望它处理10个字节的数据。实际上,你需要分别处理IP地址和端口。

以下是修正后的代码示例:

package main

import (
    "encoding/binary"
    "fmt"
    "net"
)

func main() {
    s, d := net.IP{172, 16, 100, 11}, net.IP{10, 0, 88, 11}
    var sp uint16 = 54876
    
    // 创建12字节的缓冲区(4+4+2+2,最后一个2字节留空或用于其他目的)
    buf := make([]byte, 12)
    
    // 复制源IP(4字节)
    copy(buf[0:4], s.To4())
    
    // 复制目标IP(4字节)
    copy(buf[4:8], d.To4())
    
    // 写入端口(2字节)
    binary.BigEndian.PutUint16(buf[8:10], sp)
    
    fmt.Printf("完整缓冲区: %v\n", buf)
    
    // 分别读取各部分数据
    srcIP := net.IP(buf[0:4])
    dstIP := net.IP(buf[4:8])
    port := binary.BigEndian.Uint16(buf[8:10])
    
    fmt.Printf("源IP: %v\n", srcIP)
    fmt.Printf("目标IP: %v\n", dstIP)
    fmt.Printf("端口: %d\n", port)
    
    // 如果你需要将两个IP合并为一个uint64
    ipPair := binary.BigEndian.Uint64(buf[0:8])
    fmt.Printf("IP对(uint64): %d\n", ipPair)
    
    // 从uint64恢复两个IP
    recoveredBuf := make([]byte, 8)
    binary.BigEndian.PutUint64(recoveredBuf, ipPair)
    recoveredSrcIP := net.IP(recoveredBuf[0:4])
    recoveredDstIP := net.IP(recoveredBuf[4:8])
    fmt.Printf("恢复的源IP: %v\n", recoveredSrcIP)
    fmt.Printf("恢复的目标IP: %v\n", recoveredDstIP)
}

如果你确实需要将整个数据结构编码为一个整数,可以考虑使用更大的整数类型:

// 使用uint64处理两个IP地址
func encodeIPs(src, dst net.IP) uint64 {
    var result uint64
    src4 := src.To4()
    dst4 := dst.To4()
    
    result = uint64(src4[0])<<56 | uint64(src4[1])<<48 | uint64(src4[2])<<40 | uint64(src4[3])<<32 |
             uint64(dst4[0])<<24 | uint64(dst4[1])<<16 | uint64(dst4[2])<<8 | uint64(dst4[3])
    
    return result
}

// 解码uint64为两个IP地址
func decodeIPs(encoded uint64) (net.IP, net.IP) {
    srcIP := net.IP{
        byte(encoded >> 56),
        byte(encoded >> 48 & 0xFF),
        byte(encoded >> 40 & 0xFF),
        byte(encoded >> 32 & 0xFF),
    }
    
    dstIP := net.IP{
        byte(encoded >> 24 & 0xFF),
        byte(encoded >> 16 & 0xFF),
        byte(encoded >> 8 & 0xFF),
        byte(encoded & 0xFF),
    }
    
    return srcIP, dstIP
}

关键点:

  1. binary.BigEndian.Uint32 只读取4个字节
  2. 两个IPv4地址需要8个字节,最好用 uint64 处理
  3. 端口是2字节数据,应该单独处理或与IP分开存储
  4. 考虑使用结构体来组织这些数据会更清晰
回到顶部