在go中使用来自网络的原始字节 (抱歉,问题长)我最近一直在尝试C++游戏服务器仿真器,我正在做一个项目,我在问我是否用明智的GO术语来实现它。正如您所料,服务器通过发送遵循特定协议规范的原始数据包(TCP)与一个或多个游戏客户端进行通信。相关部分如下所示:
接收头->解密它->接收字节,直到达到头长度->解密数据包的其余部分->分派给处理程序->解码数据包->根据需要处理->发送响应在go中使用来自网络的原始字节 (抱歉,问题长)我最近一直在尝试C++游戏服务器仿真器,我正在做一个项目,我在问我是否用明智的GO术语来实现它。正如您所料,服务器通过发送遵循特定协议规范的原始数据包(TCP)与一个或多个游戏客户端进行通信。相关部分如下所示:,go,network-programming,Go,Network Programming,接收头->解密它->接收字节,直到达到头长度->解密数据包的其余部分->分派给处理程序->解码数据包->根据需要处理->发送响应 协议是以字节序定义的,所以在C++实现中,包头看起来像这样(我知道,它只在LE机器上工作): 在recv()对该头进行加密和解密后,我将提取字段: // client->recv_buffer is of type u_char[1024] header = (pkt_header*) client->recv_buffer; if (client-&g
协议是以字节序定义的,所以在C++实现中,包头看起来像这样(我知道,它只在LE机器上工作):
在recv()对该头进行加密和解密后,我将提取字段:// 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
作为一个新手,我非常欢迎关于如何更有效地实现这一点的反馈。到目前为止,它工作得很好,但现在我面临的挑战是如何做相反的事情:从[]字节->结构(例如,[C8 00 03 00 01 00 00]到头{length=C8,size=03,flags=0100}
我是否需要实现与此相反的方法,或者是否有更好的方法从字节数组转换为任意结构(或者相反,与我的函数相反)?请告诉我是否有任何额外的清晰性会有所帮助。最好的方法是使用它,它在内部实现了您上面所写的内容 () 哪张照片
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}
太好了,谢谢!我应该在去写我自己的函数之前问一下。至少它很有趣。。。
// 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]
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}