Синтаксический анализ двоичного пакета (из C) в Go

#c #binary-data

#c #двоичные данные

Вопрос:

Я пишу приложение go, которое прослушивает UDP-пакеты по сети и анализирует их.

пакеты udp записываются на C, а определение структуры (согласно их документам) выглядит примерно так, как показано ниже. (Пожалуйста, поймите, что это новое для C и сетей в целом)

 typedef struct foo 
{
  int code;
  char seg[10];
  char sym[25];
  short type;
  long amtToday;
  long price;
  ...etc
} foo;
  

Пример сетевого пакета выглядит примерно так, как показано ниже

 [233 3 0 0 99 100 101 95 102 111 0 0 0 0 55 52 51 57 0 69 69 68 49 48 50 48 74 65 78 50 48 50 49 0 0 58 254 127 0 0 1 0 166 58 254 127 0 0 255 255 255 255 255 255 255 255 32 232 141 0 0 0 0 0 0 135 166 58 254 127 0 0 ... etc]
  

короче говоря, у меня возникли проблемы с получением правильных значений после sym поля.

я немного прочитал о выравнивании структуры в C и предположил, что я игнорирую дополненные значения. Но я немного смущен тем, где происходит заполнение

это так

 typedef struct foo 
{
  int code;
  char seg[10];
  **char pad[6];**
  char sym[25];
  **char pad[7];**
  short type;
  long amtToday;
  long price;
  ...etc
} foo;
  

т.е. дополнение добавляется после каждого char поля

или это больше похоже на это

 typedef struct foo 
{
  int code;
  char seg[10];
  char sym[25];
  **char pad[1];**
  short type;
  long amtToday;
  long price;
  ...etc
} foo;
  

проблема в том, что у меня нет способа определить, подходит ли какой-либо из них к моему концу. Мне нужно проанализировать всю структуру перед подтверждением, но я не могу этого сделать из-за проблемы с заполнением

или я направляюсь в неправильном направлении, анализируя этот пакет?

Ответ №1:

Вероятно, лучший способ убедиться в том, как это работает, — написать C-код, который вычисляет смещения:

 #include <stdio.h>

typedef struct foo
{
    int code;
    char seg[10];
    char sym[25];
    short type;
    long amtToday;
    long price;
} foo;

int main() {
    // What are the memory offsets between individual struct members?
    foo x;
    printf(
        "code: %ld, seg: %ld, sym: %ld, type: %ld, amtToday: %ld, price: %ldn",
        (long)amp;x.code - (long)amp;x,
        (long)amp;x.seg - (long)amp;x,
        (long)amp;x.sym - (long)amp;x,
        (long)amp;x.type - (long)amp;x,
        (long)amp;x.amtToday - (long)amp;x,
        (long)amp;x.price - (long)amp;x
    );

    // How much space does the struct take up if we create an array for it?
    foo y[2];
    printf("offset: %ldn", (long)amp;y[1] - (long)amp;y[0]);
    return 0;
}
  

Вывод:

 code: 0, seg: 4, sym: 14, type: 40, amtToday: 48, price: 56
offset: 64
  

Смещения могут зависеть от архитектуры и используемого компилятора. Если вы можете редактировать C-программу, добавление явного дополнения к структуре может быть лучшим способом гарантировать одинаковые смещения в 32-разрядных и 64-разрядных системах.

Комментарии:

1. интересно — разве type поле, являющееся коротким, не занимает всего 2 байта? почему здесь требуется 8?

2. Итак, интересная вещь здесь заключается в том, что это зависит не от «типа», а скорее от «amtToday». Поскольку amtToday является длинным, он всегда будет выровнен по 8 байтам. (если вы не используете 32-разрядную систему). Порядок элементов вашей структуры будет определять, насколько плотно ваша структура может быть упакована в памяти. Например, чередование коротких и длинных плохо с точки зрения пустой траты места. en.wikipedia.org/wiki /…

3. Спасибо! я посмотрю на статью