gpt4 book ai didi

go - 在 go 中处理来自网络的原始字节

转载 作者:IT王子 更新时间:2023-10-29 00:59:32 26 4
gpt4 key购买 nike

(抱歉,问题很长!)我最近一直在尝试使用 Go 而不是 C++ 作为一个游戏服务器模拟器,我正在作为一个副项目工作,并且质疑我是否以合理的 Go 术语来实现它。如您所料,服务器通过发送符合特定协议(protocol)规范的原始数据包 (TCP) 与一个或多个游戏客户端通信。相关部分是这样的:

接收一个包头 -> 解密它 -> 接收字节直到达到包头长度 -> 解密包的其余部分 -> 分派(dispatch)给处理程序 -> 解码包 -> 根据需要处理 -> 发送响应

协议(protocol)是根据小端顺序的字节定义的,所以在我的 C++ 实现中,包头看起来像这样(我知道,它只适用于 LE 机器):

struct pkt_header {
uint16_t length;
uint16_t type;
uint32_t flags;
};

recv()'ing 和解密此 header 后,我将提取字段:

// client->recv_buffer is of type u_char[1024]
header = (pkt_header*) client->recv_buffer;

if (client->recv_size < header->length) {
// Recv some more
}
// Decrypt and so on

在处理程序本身中,我可以将上述 header 结构嵌套在其他数据包结构定义中,并将它们转换为 byte[] 缓冲区数组,以便直接访问字段。根据我的阅读,结构对齐(不出所料)在 Go 中是困难/不可能的,并且非常不鼓励。

不知道还能做什么,我编写了这个函数以从任意 Struct -> []byte:

// Serializes the fields of a struct to an array of bytes in the order in which the fields are
// declared. Calls panic() if data is not a struct or pointer to struct.
func StructToBytes(data interface{}) []byte {
val := reflect.ValueOf(data)
valKind := val.Kind()
if valKind == reflect.Ptr {
val = reflect.ValueOf(data).Elem()
valKind = val.Kind()
}

if valKind != reflect.Struct {
panic("data must of type struct or struct ptr, got: " + valKind.String())
}

bytes := new(bytes.Buffer)
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)

switch kind := field.Kind(); kind {
case reflect.Struct:
binary.Write(bytes, binary.LittleEndian, StructToBytes(field.Interface()))
case reflect.Array, reflect.Slice:
binary.Write(bytes, binary.LittleEndian, field.Interface())
case reflect.Uint8:
binary.Write(bytes, binary.LittleEndian, uint8(field.Uint()))
case reflect.Uint16:
binary.Write(bytes, binary.LittleEndian, uint16(field.Uint()))
// You get the idea
}
}
return bytes.Bytes()
}

并且会在处理程序中执行此操作:

type Header struct {
length uint16
size uint16
flags uint32
}
newHeader := new(Header)
// Initialization, etc
client.Conn.Write(StructToBytes(newHeader)) // ex. [C8 00 03 00 00 00 01 00]

作为 Go 新手,非常欢迎提供有关我如何更有效地实现它的反馈。到目前为止它运行良好,但现在我面临着如何做相反的挑战:从 []byte->Struct(例如,[C8 00 03 00 00 01 00 00] 到 Header { length = C8, size = 03, flags = 0100 }

我是否只需要实现它的反向操作,或者是否有更好的方法从字节数组转换为任意结构(反之亦然,与我的函数相反)?如果任何额外的说明会有所帮助,请告诉我。

最佳答案

go 方法是使用 encoding/binary它在内部几乎完成了您上面所写的内容。

( playground )

package main

import (
"bytes"
"encoding/binary"
"fmt"
"log"
)

type Header struct {
Length uint16
Size uint16
Flags uint32
}

func main() {
header := &Header{Length: 0xC8, Size: 3, Flags: 0x100}
fmt.Printf("in = %#v\n", header)
buf := new(bytes.Buffer)

err := binary.Write(buf, binary.LittleEndian, header)
if err != nil {
log.Fatalf("binary.Write failed: %v", err)
}
b := buf.Bytes()
fmt.Printf("wire = % x\n", b)

var header2 Header
buf2 := bytes.NewReader(b)
err = binary.Read(buf2, binary.LittleEndian, &header2)
if err != nil {
log.Fatalf("binary.Read failed: %v", err)
}
fmt.Printf("out = %#v\n", header2)
}

哪个打印

in = &main.Header{Length:0xc8, Size:0x3, Flags:0x100}
wire = c8 00 03 00 00 01 00 00
out = main.Header{Length:0xc8, Size:0x3, Flags:0x100}

关于go - 在 go 中处理来自网络的原始字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27814408/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com