Sugestii privind decodificarea pachetelor UDP

Dezvolt o aplicație C pentru a comunica cu unul dintre dispozitivele sistemului de control real. Dispozitivul utilizează o structură bine definită a protocolului. De exemplu, ia în considerare una dintre structurile pe care dispozitivul le trimite ca pachet UDP atunci când este solicitat:

typedef struct poll_request_s {
   uint16             poll_number; /* poll number mirrored from the 
                                    * poll request */
   uint16             length;      /* length of the message */

   /* till above it was all header section this is ACTUAL DATA */
   attribute_list_t   attr_list;   /* this attribute list contains 
                                    * various attributes */
} poll_request_t

Acum, attribute_list_t este o structură care împachetează diferite atribute și fiecare atribut din această listă este identificat de un număr de identificator care este uint16 (16 biți întregi). Deci, în protocolul scurt funcționează ceva de genul: -

  • Solicitați unele date.
  • Obțineți datele sub formă de listă de atribute.
  • Fiecare atribut din lista de atribute conține un identificator de obiect.
  • Parsează fiecare atribut (conversie în ordine de octet gazdă) folosind acest identificator de obiect.
  • Atributul în sine poate conține mai multe listă de atribute. (Atribut inițial)

Această structură atrtribute_list_t este ceva de genul de mai jos:

typdef struct attribute_list_s {
   uint16  length;       /* length of attribute list */
   uint16  count;        /* number of attributes in this list */
   uint8   attrs_data[]; /* another container to hold attributes' data */
} attribute_list_t

Acum, attrs_data </​​code> este doar un suport pentru păstrarea tuturor atributelor din listă. De fapt, acest attrs_data </​​code> trebuie să fie realizat într-o altă structură numită ava_type pentru a citi informațiile despre atribute.

typdef struct ava_type_s {
   uint16 attr_id; /* type of attribute */
   uint16 length;  /* length of this attribute 
                    *(this length of single attribute not whole list*/
   uint8  data[];  /* another flexible array to hold data for this 
                    * attribute type */
}

Acum, pentru a itera și analiza atributele din cadrul acestei structuri, folosesc în prezent acest algoritm (pseudo-cod de mai jos):

uint8* packet = recv_packet(SOCKET);
/* this is used as packet iterator pointer */
unit8* packet_ptr = packet;
parsed_packet_t parsed_packet = malloc(SOME_SIZE);
.
. /* do header un-packing */
.
/* dont need attribute_list length so skip this 2 bytes */
parsed_packet += 2;

/* parsed packet do nee count of attributes */
parsed_packet.attribute_list->count = NTOHS(packet_ptr);
packed_ptr += 2; /* skip count */

/* now packet_ptr is pointer to attr_list */
offset = 0, i = 0;
for(i = 0 to attr_list->count) {
   /* cast the attributes' data to ava_type */
   packet_ptr += offset;

   /* parse object identifier */
   parsed_packet.attribute_list->data[i++].object_id = NTOHS(packet_ptr);
   packet_ptr += 2; /* skip 2 bytes */

   /* next offset would be attribute length of this packet */
   attribute_length += 2 + NTOHS(packet_ptr);
   packet_ptr += 2;

   /* now we are pointer to actual data of i(th) attribute */

   /* I've made this parser structure and hash table to
    * retrieve the parser for particular attr_id */
   parser* p = HASH_TABLE(ava_type->attr_id);

   /* parser has function point for network order to host 
    * order and visa-versa */
   p->ntoh(ava_type, parsed_packet.attribute_list->data[i]);
}

Acum, întrebările mele sunt:

  • Chiar dacă am abordat HASH_TABLE în algoritmul de mai sus, dar în realitate folosesc 20 până la 30 IF-ELSE . Din moment ce C nu are table hash în stdlib . Există aproximativ 600 de structuri în protocol și nu vreau să scriu 600 dacă-altceva . Ce sugestii și metode dați despre parsarea acestor structuri conform codului lor attribute_id .
  • O altă problemă este compilarea în structurile pe care le-am definit. Toată structura mea este definită cu câmpul flexible array pentru containerul de date. Acum, când primesc mesajul, ele conțin length pentru aproape fiecare atribut, dar această lungime nu poate fi folosită pentru malloc..ing structura parsată ca compilator poate adăuga în mod magic niște octeți de padding și nu am decât octeți. Sunt, de obicei, malloc..ing despre octeți lenght + 300 în scopuri de siguranță. De fapt, acest lucru mi se pare o practica gresita de gestionare a memoriei. Orice sugestii cu privire la această problemă?

malloc..ing the structure to parse the received messages is the biggest problem for me so far. I want some memory efficient and fast way to do it?

De asemenea, dacă ați făcut deja astfel de proiecte, ați putea să vă împărtășiți abordarea? Orice sugestii sau comentarii pentru a mă pune în direcția corectă? Vreau un design simplu, fără a complica lucrurile în mod inutil.

1
trimiterea de gânduri rele pentru tine pentru utilizarea fără sens a tipcast
adăugat autor tbert, sursa

1 răspunsuri

I puternic vă recomandăm să nu utilizați structuri C pentru a vă defini protocolul de rețea. C structurile de structuri depind de:

  1. Hardware-ul
  2. Compilatorul
  3. Versiunea compilatorului
  4. Codul sursă
  5. #pragmasul încorporat în codul sursă, dacă este cazul
  6. Opțiunile compilatorului în vigoare la compilarea codului sursă

Utilizați XDR sau ceva care vă va oferi un format standard. Ar trebui să puteți defini exact ceea ce aveți în prezent în XDR și să efectuați automat codarea și decodarea pentru dvs.

2
adăugat
Trebuie să reținem că este posibil să o faceți și manual, scriindu-vă propriile funcții flatten ()/unflatten() pentru memcpy() fiecare valoare din structura dvs. într-o matrice octet și invers (opțional cu schimbarea endian ca bine, dacă doriți să specificați că). Este un pic obositoare, dar păstrează algoritmul de rețea independent de compilatorul gotchas EJP enumerat mai sus.
adăugat autor Jeremy Friesner, sursa
Multumesc pentru raspuns! Sună interesant, dar de fapt trebuie să filtrez aceste date și să efectuez unele operații logice și actualizarea GUI? Se pare că XDR este doar un mod de reprezentare a datelor? Pot folosi acest lucru pentru a controla un dispozitiv în timp real? Orice link sau mai multe informații despre XDR ar fi de ajutor.
adăugat autor Shivam, sursa
XDR reprezintă reprezentarea datelor eXternal. Este în esență o limbă de definire a interfeței (IDL) care compilează codul C și vă puteți scrie propriile extensii. Puteți să-l utilizați în flux sau, în cazul tău, în memorie. Nu face altceva. A fost parte din SUN RPC. Este construit în majoritatea Unixurilor și Linux-urilor din câte știu eu. Încercați man rpcgen . Dacă protocolul este definit de dispozitivul pe care îl puteți sau nu poate să-l cartografiați în XDR, dar la o privire rapidă nu văd nimic despre acest lucru nu va hărți.
adăugat autor EJP, sursa