- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
(抱歉,问题很长!)我最近一直在尝试使用 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/
美好的一天!我试图添加两个字节变量并注意到奇怪的结果。 byte valueA = 255; byte valueB = 1; byte valueC = (byte)(valueA + valueB
嗨,我是 swift 的新手,我正在尝试解码以 [Byte] 形式发回给我的字节数组?当我尝试使用 if let string = String(bytes: d, encoding: .utf8)
我正在使用 ipv4 和 ipv6 存储在 postgres 数据库中。 因为 ipv4 需要 32 位(4 字节)而 ipv6 需要 128(16 字节)位。那么为什么在 postgres 中 CI
我很好奇为什么 Go 不提供 []byte(*string) 方法。从性能的角度来看,[]byte(string) 不会复制输入参数并增加更多成本(尽管这看起来很奇怪,因为字符串是不可变的,为什么要复
我正在尝试为UDP实现Stop-and-Wait ARQ。根据停止等待约定,我在 0 和 1 之间切换 ACK。 正确的 ACK 定义为正确的序列号(0 或 1)AND消息长度。 以下片段是我的代码的
我在下面写了一些代码,目前我正在测试,所以代码中没有数据库查询。 下面的代码显示 if(filesize($filename) != 0) 总是转到 else,即使文件不是 0 字节而是 16 字节那
我使用 Apache poi 3.8 来读取 xls 文件,但出现异常: java.io.IOException: Unable to read entire header; 0 by
字典大小为 72 字节(根据 getsizeof(dict) 在字典上调用 .clear() 之后发生了什么,当新实例化的字典返回 240 字节时? 我知道一个简单的 dict 的起始大小为“8”,并
我目前正在努力创建一个函数,它接受两个 4 字节无符号整数,并返回一个 8 字节无符号长整数。我试图将我的工作基于 this research 描述的方法,但我的所有尝试都没有成功。我正在处理的具体输
看看这个简单的程序: #include using namespace std; int main() { unsigned int i=0x3f800000; float* p=(float*)(
我创建了自己的函数,将一个字符串转换为其等效的 BCD 格式的 bytes[]。然后我将此字节发送到 DataOutputStram (使用需要 byte[] 数组的写入方法)。问题出在数字字符串“8
此分配器将在具有静态内存的嵌入式系统中使用(即,没有可用的系统堆,因此“堆”将只是“char heap[4096]”) 周围似乎有很多“小型内存分配器”,但我正在寻找能够处理非常小的分配的一个。我说的
我将数据库脚本从 64 位系统传输到 32 位系统。当我执行脚本时,出现以下错误, Warning! The maximum key length is 900 bytes. The index 'U
想知道 128 字节 ext2 和 256 字节 ext3 文件系统之间的 inode 数据结构差异。 我一直在为 ext2、128 字节 inode 使用此引用:http://www.nongnu.
我试图理解使用 MD5 哈希作为 Cassandra key 在“内存/存储消耗”方面的含义: 我的内容(在 Java 中)的 MD5 哈希 = byte[] 长 16 个字节。 (16 字节来自维基
检查其他人是否也遇到类似问题。 shell脚本中的代码: ## Convert file into Unix format first. ## THIS is IMPORTANT. ###
我们有一个测量数据处理应用程序,目前所有数据都保存为 C++ float,这意味着在我们的 x86/Windows 平台上为 32 位/4 字节。 (32 位 Windows 应用程序)。 由于精度成
我读到在 Java 中 long 类型可以提升为 float 和 double ( http://www.javatpoint.com/method-overloading-in-java )。我想问
我有一个包含 n 个十进制元素的列表,其中每个元素都是两个字节长。 可以说: x = [9000 , 5000 , 2000 , 400] 这个想法是将每个元素拆分为 MSB 和 LSB 并将其存储在
我使用以下代码进行 AES-128 加密来编码一个 16 字节的 block ,但编码值的长度给出了 2 个 32 字节的 block 。我错过了什么吗? plainEnc = AES.enc
我是一名优秀的程序员,十分优秀!