2013-09-09 2 views
1

Если кто-то получит эту проблему в будущем, я оставлю это.разбиение массива символов на структуру

* Примечание. Этот подход не будет работать при переходе с сервера C на сервер C. Это будет работать только с клиентом Java на сервере C. Поэтому мне пришлось отказаться от этого подхода.

Хорошо, я слишком долго сражался с С. Я передаю некоторую информацию с UDP с java-клиента на сервер C. Я могу получить информацию, но я не уверен, как развалится сообщение для хранения в структуры, как так

struct __attribute__((__packed__)) clientMessage 
{ 
    short tml; 
    short rid; 
    char op;   
    char message[MAXBUFLEN-5]; 
}; 

Я получаю сообщение, как этот Где тест является char test[MAXBUFLEN-5];

if ((numbytes = recvfrom(sockfd, test, MAXBUFLEN-1, 0, 
    (struct sockaddr *)&their_addr, &addr_len)) == -1) { 
    perror("recvfrom"); 
    exit(1);} 

Итак, мне нужно принять сообщение «7 2 1Yo» (два коротких байта длиной 2 байта и символ с последующей неизвестной длиной сообщения) и сохранить его в соответствующих частях структуры. Сообщение отправляется правильно, я просто не могу разбить его на бит информации, которая мне нужна. Я в настоящее время пытается

memcpy(&cm.rid, &test, 2); 
memcpy(&cm.tml, &test[1], 2); 
memcpy(&cm.op, &test[4], 1); 
memcpy(&cm.message, &test[5], MAXBUFLEN-5); 

Но мои resutls в конечном итоге

Message: Yo 
OP: 1Yo 
RID: 7 1Yo 
TML: 2 7 1Yo 

это должно быть

Message: Yo 
OP: 1 
RID: 2 
TML: 7 

я успешно получаю сообщение, но ничего другого. Я относительно новичок в C, поэтому простите мое невежество. Я предполагаю, что это очень просто, но idk.

+0

По '// empty', вы имеете в виду' 0'? Почему это не 'char test [MAXBUFLEN]'? Почему содержимое 'test' инвертирует порядок' rid' и 'tml' в вашей структуре? Вы передаете указатель на массив в memcpy() как исходный адрес (вы не заметите разницы, если 'test' - массив, но он неправильного типа). Вы можете исправить, удалив '&', если вы имели в виду '& test [0]'. Не должно быть 'memcpy (& cm.tml, & test [2], 2);'? – jxh

+1

Вы считали вопросы, связанные с вопросом? Кроме того, если 'rid' и' tml' являются двумя байтами, почему вы memcpy-ing в 'tml' из' & test [1] '? – MatthewD

+0

Я бы также предложил упорядочить ваши члены структуры в соответствии с порядком их появления в сетевом потоке, ради здравого смысла. – MatthewD

ответ

0

Первая строка должна быть memcpy(&cm.rid, &test[0], 2);, так как адрес должен быть адресом первого байта.

А остальное:

memcpy(&cm.tml, &test[2], 2); // you want to get the third and forth byte, begin with index 2. 
memcpy(&cm.op, &test[4], 1); // the fifth byte, begin with index 4. 
memcpy(&cm.message, &test[5], MAXBUFLEN-5); // the rest bytes. 
+1

test, and & test [0] - то же самое –

+1

@ScottyBauer Да, я просто хочу придерживаться авторского кода. – lulyon

+0

Ах ладно, звучит хорошо! –

0

Поскольку test содержит строку "7 2 1Yo", вы должны разобрать строку в значение, которые вы хотите. Вы можете сделать это с sscanf():

char fmt[256]; 
snprintf(fmt, sizeof(fmt), "%%hd %%hd %%c%%%ds", MAXBUFLEN-5-1); 
sscanf(test, fmt, &cm.rid, &cm.tml, &cm.op, cm.message); 

В этом фрагменте кода мы создаем строку формата для синтаксического анализа. Это необходимо для предотвращения того, чтобы sscanf() просматривал сообщение в конце сообщения в случае, если оно не завершено \0. Результат snprintf() вызова с MAXBUFLEN 128 является:

"%hd %hd %c%122s" 

Который говорит sscanf() для сканирования двух коротких десятичных чисел, в char, и строка длиной не более 122 символов.

0

Если вы используете двоичный протокол, лучше использовать его, например. int16_t вместо короткого в объявлении clientMessage, потому что размер коротки не указан в стандарте c.

Чтобы получить доступ к сообщению, сохраненное в test можно сделать просто что-то подобное:

struct clientMessage *cm = (struct clientMessage *) test; 

Необходим также заметить, что порядок байты сетевых протоколов отличаются от байт в виде x86 и amd64 архитектуры, так вместо 42 вы можете получить 10752. Чтобы исправить это, вы можете использовать функцию ntohs() (Network TO Host Short) для доступа к tm и rid.

+0

'sizeof (short)' не указан в C, но его диапазон _minimum_ указан в _least_ -32767 до 32767, поэтому 'short' может хранить все целые числа, которые' int16_t' могут с единственным потенциальным исключением -32768. В любом случае, я тоже предпочитаю 'int16_t' над' short'. – chux

+0

@chux: Дело в том, что вы не хотите, чтобы он был больше. Если другой конец соединения ожидает два байта, вы не хотите случайно отправлять его четыре, только потому, что реализация на этой стороне соединения превышает минимальную и имеет 32-битное короткое замыкание. –

+0

@Paul Griffiths Моя забота о Ruge Bolek post заключалась в том, что «размер коротки не указан», хотя это правда, вводит в заблуждение, поскольку существуют ограничения относительно того, что может быть коротким. Проблема OP - это обмен сообщениями между Java short и C _something_. C-тип 'int16_t', где доступно, соответствует краткости Java, что делает его предпочтительным типом.Если 'int16_t' не будет доступен, получающей стороне, возможно, придется прибегать к более крупным типам, и, конечно же, при отправке следует определить свои значения. – chux

0

Использование sscanf() для первой части и тетсра() для текста.

const char *message = "7 2 1Yo"; 
struct clientMessag cM; 
int offset = 0; 
int n; 
n = sscanf(message, "%hd %hd %c%n", &cM.tml, &cM.rid, &cM.op, &offset); 
size_t SuffixLength = strlen(&message[offset]); 
if ((n != 3) || (SuffixLength >= sizeof(cM.message))) { 
    exit(1); // handle syntax error; 
} 
memcpy(cM.message, &message[offset], SuffixLength + 1); 
// Additional field checks like IsOKOpCode(cM.op) 

Я избегал %s как он не хранит пробелы в сообщение.
Проверка ошибок всегда хорошо. Рекомендовать дополнительные полевые проверки.


КСТАТИ: его не ясно, если cM.op поле должно быть лакомство в виде текста или числа. Требует ли OP 1 или «1»? Вышеприведенный текст. В качестве альтернативы можно использовать "%hd%hd%hhd%n".

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