2014-10-14 4 views
6

Я пишу клиент-серверное приложение в Go. Я хочу выполнить кастинг типа C в Go.Переход преобразования между массивом struct и byte

E.g. в Go

type packet struct { 
    opcode uint16 
    data [1024]byte 
} 

var pkt1 packet 
... 
n, raddr, err := conn.ReadFromUDP(pkt1) // error here 

Также я хочу, чтобы выполнить C-подобный тетсру(), которая позволит мне непосредственно сопоставить поток сети байт, полученный на структуру.

например. с выше получил PKT1

type file_info struct { 
    file_size uint32  // 4 bytes 
    file_name [1020]byte 
} 

var file file_info 
if (pkt1.opcode == WRITE) { 
    memcpy(&file, pkt1.data, 1024) 
} 
+2

Я рекомендую попробовать записать его в ходу первого. Вы просто не делали бы ничего подобного. Помимо прочего, у go нет кастинга. 'uint' также не 4 байта. 'Conn.Read' принимает' [] byte', который является эффективным интеллектуальным указателем размера в массив подстановки. У вас будет намного лучшее время, просто записывая это в go. – Dustin

+1

Вы уже видели встроенную двоичную сериализацию с пакетом 'encoding/gob'? – dyoo

ответ

2

Вы должны были бы использовать небезопасно, также uint 8 байт на 64-битных системах, вы должны использовать uint32, если вы хотите 4 байта.

Это уродливое, небезопасное, и вам нужно самому справиться с энтузиазмом.

type packet struct { 
    opcode uint16 
    data [1022]byte 
} 

type file_info struct { 
    file_size uint32  // 4 bytes 
    file_name [1018]byte //this struct has to fit in packet.data 
} 

func makeData() []byte { 
    fi := file_info{file_size: 1 << 20} 
    copy(fi.file_name[:], []byte("test.x64")) 
    p := packet{ 
     opcode: 1, 
     data: *(*[1022]byte)(unsafe.Pointer(&fi)), 
    } 
    mem := *(*[1022]byte)(unsafe.Pointer(&p)) 
    return mem[:] 
} 

func main() { 
    data := makeData() 
    fmt.Println(data) 
    p := (*packet)(unsafe.Pointer(&data[0])) 
    if p.opcode == 1 { 
     fi := (*file_info)(unsafe.Pointer(&p.data[0])) 
     fmt.Println(fi.file_size, string(fi.file_name[:8])) 
    } 
} 

play

13

unsafe.Pointer, хорошо, небезопасно, и вы на самом деле не нужно здесь. Используйте encoding/binary пакет вместо:

// Create a struct and write it. 
t := T{A: 0xEEFFEEFF, B: 3.14} 
buf := &bytes.Buffer{} 
err := binary.Write(buf, binary.BigEndian, t) 
if err != nil { 
    panic(err) 
} 
fmt.Println(buf.Bytes()) 

// Read into an empty struct. 
t = T{} 
err = binary.Read(buf, binary.BigEndian, &t) 
if err != nil { 
    panic(err) 
} 
fmt.Printf("%x %f", t.A, t.B) 

Playground

Как вы можете видеть, он обрабатывает размеры и порядок байт довольно аккуратно.

2

Спасибо за ответы, и я уверен, что они отлично работают. Но в моем случае меня больше интересовал синтаксический анализ [] байтового буфера, принятого в качестве сетевого пакета. Я использовал следующий метод для разбора буфера.

var data []byte // holds the network packet received 
opcode := binary.BigEndian.Uint16(data) // this will get first 2 bytes to be interpreted as uint16 number 
raw_data := data[2:len(data)] // this will copy rest of the raw data in to raw_data byte stream 

При построении [] поток байтов из структуры, вы можете использовать следующий метод

type packet struct { 
    opcode uint16 
    blk_no uint16 
    data string 
} 
pkt := packet{opcode: 2, blk_no: 1, data: "testing"} 
var buf []byte = make([]byte, 50) // make sure the data string is less than 46 bytes 
offset := 0 
binary.BigEndian.PutUint16(buf[offset:], pkt.opcode) 
offset = offset + 2 
binary.BigEndian.PutUint16(buf[offset:], pkt.blk_no) 
offset = offset + 2 
bytes_copied := copy(buf[offset:], pkt.data) 

Я надеюсь, что это дает общее представление о том, как преобразовать [] поток байтов на структуру и STRUCT обратно [] байтовый поток.

1

У меня была такая же проблема, и я решил ее с помощью пакета «encoding/binary». Вот пример:

package main 

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

func main() { 
    p := fmt.Println 
    b := []byte{43, 1, 0} 

    myStruct := MyStruct{} 
    err := binary.Read(bytes.NewBuffer(b[:]), binary.BigEndian, &myStruct) 

    if err != nil { 
    panic(err) 
    } 

    p(myStruct) 
} 

type MyStruct struct { 
    Num uint8 
    Num2 uint16 
} 

Вот пример работы: https://play.golang.org/p/Q3LjaAWDMh

Смежные вопросы