将结构体转换为字节切片([]byte)的方法在Go语言中如下所示:

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

Convert struct to []byte with Go

问题

我有一个数据包结构,我希望将其序列化为二进制格式,以便通过网络发送。

有许多数据包结构,但我将以登录数据包作为示例:

  1. login结构体 {
  2. seq uint8
  3. id uint16
  4. username [16]string
  5. password [16]string
  6. unknown1 [16]byte
  7. }

我在某个地方读到,对于非固定大小的结构体,不能使用binary.Write。但我相信我的结构体是固定大小的(如果我错了,请纠正我,我可能非常错误)。

现在使用以下代码:

  1. var buf bytes.Buffer
  2. x := login{
  3. seq: 2,
  4. id: 1,
  5. username: [16]string{"username"},
  6. password: [16]string{"password"},
  7. }
  8. err := binary.Write(&buf, binary.LittleEndian, x)
  9. if err != nil {
  10. log.Fatalln(err)
  11. }

这给我报错:binary.Write: invalid type main.login

现在,有没有办法解决这个问题?有没有其他方法?就像在C中可以使用结构体并通过网络发送一样。

英文:

I have a packet structure and I wish to serialize it into binary so I can send it through the wire.

There are many packet structures but I'll give the login packet as an example:

  1. login struct {
  2. seq uint8
  3. id uint16
  4. username [16]string
  5. password [16]string
  6. unknown1 [16]byte
  7. }

I've read somewhere that you can't use binary.Write for non-fixed size structures. But I believe my structure is fixed size (correct me if I'm wrong, I could be very wrong).

Now using this code:

  1. var buf bytes.Buffer
  2. x := login{
  3. seq: 2,
  4. id: 1,
  5. username: [16]string{"username"},
  6. password: [16]string{"password"},
  7. }
  8. err := binary.Write(&buf, binary.LittleEndian, x)
  9. if err != nil {
  10. log.Fatalln(err)
  11. }

Gives me the error: binary.Write: invalid type main.login

Now, is there a way to fix this? Is there an alternative approach? Much like how you can use structs in C and send it through the network.

答案1

得分: 5

你的代码中有两个错误。首先,你的结构体字段应该是可导出的,这样encoding/binary才能看到它。

其次,[16]string表示一个包含16个字符串的数组,而不是一个16字节的字符串。所以你的结构体应该像这样:

  1. type login struct {
  2. Seq uint8
  3. ID uint16
  4. Username [16]byte
  5. Password [16]byte
  6. Unknown1 [16]byte
  7. }

然后它就可以工作了:https://play.golang.org/p/Nq8fRqgkcp。

英文:

You have two errors in your code. Firstly, your struct fields should be exported for encoding/binary to see it.

Secondly, [16]string means an array of 16 strings, not a 16-byte string. So your struct should look like this:

  1. type login struct {
  2. Seq uint8
  3. ID uint16
  4. Username [16]byte
  5. Password [16]byte
  6. Unknown1 [16]byte
  7. }

Then it works: https://play.golang.org/p/Nq8fRqgkcp.

答案2

得分: 5

你可以使用unsafe包来实现这个。

  1. type test struct {
  2. a int
  3. s string
  4. }
  5. v1 := test{
  6. a: 5,
  7. s: "sdaf",
  8. }
  9. fmt.Printf("v1: %#v\n", v1)
  10. b := *(*[unsafe.Sizeof(v1)]byte)(unsafe.Pointer(&v1))
  11. fmt.Printf("bytes: %#v\n", b)
  12. v2 := *(*test)(unsafe.Pointer(&b))
  13. fmt.Printf("v2: %#v\n", v2)

请注意,unsafe包提供了一种绕过Go语言类型系统的方法,因此使用时需要特别小心。

英文:

You can do that using the unsafe package.

  1. type test struct {
  2. a int
  3. s string
  4. }
  5. v1 := test{
  6. a: 5,
  7. s: "sdaf",
  8. }
  9. fmt.Printf("v1: %#v\n", v1)
  10. b := *(*[unsafe.Sizeof(v1)]byte)(unsafe.Pointer(&v1))
  11. fmt.Printf("bytes: %#v\n", b)
  12. v2 := *(*test)(unsafe.Pointer(&b))
  13. fmt.Printf("v2: %#v\n", v2)

huangapple
  • 本文由 发表于 2017年2月7日 00:07:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/42072214.html
匿名

发表评论

匿名网友

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

确定