Невозможно использовать структуру для хранения и последующей печати данных udp через recvfrom - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь использовать следующую структуру для помещения полученных данных:

typedef struct packet {
  uint8_t magic;
  uint8_t version;
  uint16_t body_length;
  char *body;
} packet;

Это функция печати:

void displayPacket (struct packet p){
  printf("Magic : %u\n",p.magic);
  printf("Version : %u\n",p.version);
  printf("Body Length: %d\n",ntohs(p.body_length));
  printf("Body : %s\n",p.body);
}

В моем основном я пытаясь сохранить полученные данные в моей структуре:

unsigned char reply[1024];
  struct packet reply_packet;
  reply_packet.body = malloc(1021);
  reply_packet.body[1020] = '\0';
  rc = recvfrom(s,&reply_packet,sizeof(reply_packet),0,NULL,NULL);
  displayPacket(reply_packet);
  free(reply_packet.body);
  close(s);

Вывод:

Magic : 95
Version : 1
Body Length: 1008
[1]    4741 segmentation fault  ./network

Magi c, Version, Body Length - ожидаемый вывод начала пакета , Максимальный размер лимита пакета составляет 1024 байта из-за протокола, за которым следуют другие одноранговые узлы.

Однако у меня есть ошибка сегментации, вызванная моей функцией displayPacket, точнее, этой строкой:

printf("Body : %s\n",p.body);

Это вывод valgrind, если он может помочь:

==4886== Invalid read of size 1
==4886==    at 0x4C32CF2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4886==    by 0x4E994D2: vfprintf (vfprintf.c:1643)
==4886==    by 0x4EA0F25: printf (printf.c:33)
==4886==    by 0x108EFD: displayPacket (network.c:143)
==4886==    by 0x1090FF: main (network.c:189)
==4886==  Address 0x3030000000000000 is not stack'd, malloc'd or (recently) free'd
==4886== 
==4886== 
==4886== Process terminating with default action of signal 11 (SIGSEGV)
==4886==  General Protection Fault
==4886==    at 0x4C32CF2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4886==    by 0x4E994D2: vfprintf (vfprintf.c:1643)
==4886==    by 0x4EA0F25: printf (printf.c:33)
==4886==    by 0x108EFD: displayPacket (network.c:143)
==4886==    by 0x1090FF: main (network.c:189)

Это доставляет мне много часов, даже если это кажется довольно тривиальным ...

Ожидаемый вывод будет соответствовать содержимому остальной части содержимого в пакете. До сих пор я был в состоянии сделать это.

Какие решения вы бы хотели решить эту проблему, пожалуйста?

Спасибо.

РЕДАКТИРОВАТЬ 1:

Решена проблема ошибки сегментации путем изменения структуры следующим образом:

typedef struct packet {
  uint8_t magic;
  uint8_t version;
  uint16_t body_length;
  char body[1021];
} packet;

и остальной код:

unsigned char reply[1024];
  struct packet reply_packet;
  reply_packet.body[1020] = '\0';
  rc = recvfrom(s,&reply_packet,sizeof(reply_packet),0,NULL,NULL);
  printf("body[0] %d\n",reply_packet.body[0]);
  displayPacket(reply_packet);
  close(s);

displayPacket остался без изменений.

1 Ответ

0 голосов
/ 18 апреля 2020

package.body - указатель. На самом деле не имеет смысла передавать указатель, поскольку адрес данных на удаленной машине бесполезен, плюс вы всегда будете читать только байты sizeof (указателя) для тела. Вы можете сделать что-то вроде этого:

typedef struct packet {
  uint8_t magic;
  uint8_t version;
  uint16_t body_length;
  char body[MAX_BODY_SIZE];
} packet;

Вы зависаете в printf, потому что вы разыменовываете неверный указатель. Даже если body имеет переменную длину, вы можете установить для MAX_BODY_SIZE максимально возможный размер, а затем использовать поле body_length для определения фактического размера.

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

Обновление: вы близки. Вы печатаете тело как число. Так как вы упомянули ASCII, я предполагаю, что это строка. Кроме того, вам нужно NULL прекратить на основе фактической длины тела. Вот что вам нужно:

struct packet reply_packet;
  rc = recvfrom(s,&reply_packet,sizeof(reply_packet),0,NULL,NULL);
  reply_packet.body[packet.body_length] = '\0';     // null term after the body length 
  printf("body[0] %s\n",reply_packet.body);  // change to %s and remove [0], you want the pointer not a character
  displayPacket(reply_packet);
...