2016-12-09 2 views
1

Хотя это может быть дубликат сообщения, я хотел бы убедиться, как он работает в моем конкретном коде.C: Отправить вложенную структуру через TCP-сокет

Чего я хочу достичь?

Отправка и получение структуры по TCP/IP-соединению.

Что у меня есть?

Sender

инициализации структур:

typedef struct soutputdata { 
    unsigned long long ull_date; 
    unsigned int ui_ixl; 
    unsigned int ui_type; 
    unsigned int ui_index; 
    char c_values[64][2]; 
    int i_valueid; 
} s_OUTPUTDATA; 

typedef struct sheader { 
    int i_head; 
} s_HEADER; 

typedef struct soutdata { 
    s_HEADER *sHeader; 
    s_OUTPUTDATA *sDATAout; 
} s_OUTDATA; 

Теперь я хочу, чтобы отправить s_OUTDATA-структуру для подключенного клиента TCP.

выделения памяти (это правильно?):

s_OUTDATA *poutData = malloc(sizeof(s_OUTDATA)); 
poutData->sDATAout = malloc(sizeof(s_OUTPUTDATA)); 
poutData->sHeader = malloc(sizeof(s_HEADER)); 

Отправка-структуру (, как я могу получить правильный размер всего s_OUTDATA структуры?):

if ((send(sendSocket, poutData, 1024, 0)) == -1) { 
     fprintf(errlog, "%.3f error: %s(): Failure Sending Message!\n", gettime(), __func__); 
     close(sendSocket); 
    } 

Получатель

инициализации структур:

typedef struct soutputdata { 
    unsigned long long ull_date; 
    unsigned int ui_ixl; 
    unsigned int ui_type; 
    unsigned int ui_index; 
    char c_values[64][2]; 
    int i_valueid; 
} s_OUTPUTDATA; 

typedef struct sheader { 
    int i_head; 
} s_HEADER; 

typedef struct soutdata { 
    s_HEADER *sHeader; 
    s_OUTPUTDATA *sDATAout; 
} s_OUTDATA; 

выделения памяти (это правильно?):

s_OUTDATA *p = malloc(sizeof(s_OUTDATA)); 
poutData->sDATAout = malloc(sizeof(s_OUTPUTDATA)); 
poutData->sHeader = malloc(sizeof(s_HEADER)); 

получающего-структуру:

if ((num = recv(newSocket, p, 1024,0)) == -1) { 
    perror("recv"); 
    exit(1); 
} 
else if (num == 0) { 
    printf("Connection closed\n"); 
} 

Что такое проблема?

При попытке работать с полученными данными я получаю ошибку в сегментации.

printf("ui_index: %d\n", p->sDATAout->ui_index); 

Что мне не хватает?

Я предполагаю, что я сделал неправильный с распределением памяти, но я не уверен, что и как его решить.

ответ

1

Посмотрите на структуры вы отправляете:

typedef struct soutdata { 
    s_HEADER *sHeader; 
    s_OUTPUTDATA *sDATAout; 
} s_OUTDATA; 

Это не содержит экземпляров из s_HEADER и s_OUTPUTDATA, но указателей к этим структурам. Поэтому вы не отправляете данные, а указатели.

Поскольку адреса указателей имеют смысл только для процесса, который их создал, эти указатели на принимающей стороне не указывают на допустимую ячейку памяти, поэтому разыменование этих указателей приводит к undefined behavior.

Вместо того, чтобы содержать указатели, изменить-структуру, чтобы содержать фактические данные:

typedef struct soutdata { 
    s_HEADER sHeader; 
    s_OUTPUTDATA sDATAout; 
} s_OUTDATA; 

Затем вы посылаете, давая размер структуры:

send(sendSocket, p, sizeof(s_OUTDATA), 0) 

Что еще вам нужно обратиться на endianness и структура обивка.

В некоторых системах сначала хранятся целочисленные типы с наименее значимым байтом (LSB), в то время как другие начинают сначала с самого важного байта (MSB). Функции htonl и htons могут преобразовывать 32-разрядные и 16-разрядные значения соответственно из порядка байтов хоста (LSB или MSB) в сетевой байтовый порядок (MSB), а ntohl и ntohs выполняют обратную функцию этих двух функций.

A struct может содержать некоторое количество отступов между элементами или в конце. Как это откладывается, зависит от реализации. Таким образом, двоичная компоновка struct на одной системе может быть не такой, как в другой системе.

Работа с заполнением может быть решена путем отправки каждого поля данных отдельно вместо целых структур, чтобы переданные данные находились в известном формате. В качестве альтернативы вы можете использовать this guide to structure packing для построения своих структур таким образом, чтобы потенциально исключить заполнение или уменьшить его до известной суммы в конце.

+0

спасибо за быстрый ответ. Ничего себе, это полностью упустило. но теперь я получаю компиляционную ошибку при работе с указателем обеих структур (потому что они больше не существуют). Нужно ли менять все на экземпляры? – Frechdachs

+0

@Frechdachs Да, поскольку типы данных членов изменились, вам необходимо обратиться к их использованию. То есть 'p-> sHeader.i_head' вместо' p-> sHeader-> i_head'. – dbush

+0

ОК, черт возьми. потому что я имею, например, функцию с указателем на структуру s_OUTPUTDATA в качестве возврата, и теперь мне нужно вернуть всю структуру, которая просто слишком тяжелая. или я могу передать содержимое указателя в экземпляр? – Frechdachs

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