2009-03-23 4 views
1

Следуя моему предыдущему вопросу (Why do I get weird results when reading an array of integers from a TCP socket?), я придумал следующий код, который, похоже, работает. Образец кода хорошо работает с небольшим количеством элементов массива, но как только он становится большим, данные коррумпированы к концу.При отправке массива int по TCP, почему только первая сумма правильная?

Это код, чтобы отправить массив междунар через TCP:

#define ARRAY_LEN 262144 

long *sourceArrayPointer = getSourceArray(); 

long sourceArray[ARRAY_LEN]; 
for (int i = 0; i < ARRAY_LEN; i++) 
{ 
    sourceArray[i] = sourceArrayPointer[i]; 
} 

int result = send(clientSocketFD, sourceArray, sizeof(long) * ARRAY_LEN); 

И это код, получить массив INT:

#define ARRAY_LEN 262144 

long targetArray[ARRAY_LEN]; 
int result = read(socketFD, targetArray, sizeof(long) * ARRAY_LEN); 

Первые несколько чисел в порядке, но дальше по массиву цифры начинают совершенно разные. В конце, когда цифры должны выглядеть так:

0 
0 
0 
0 
0 
0 
0 
0 
0 
0 

Но они на самом деле выглядят как это?

4310701 
0 
-12288 
32767 
-1 
-1 
10 
0 
-12288 
32767 

Это потому, что я использую неправильный размер отправки/получения?

+0

Кстати, нет смысла копировать содержимое массива в переменную локального массива перед отправкой - это просто трата памяти и циклов процессора. –

+0

Когда я попытался использовать указатель вместо копирования в массив, напишите return -1. Вот почему я использую метод copy to array. –

ответ

7

Звонок read(..., len) не считывает len байтов из сокета, он считывает максимум len байт. Ваш массив довольно большой, и он будет разделен на многие пакеты TCP/IP, поэтому ваш вызов читать, вероятно, возвращает только часть массива, в то время как остальная часть по-прежнему «находится в пути». read() возвращает количество полученных байтов, поэтому вы должны позвонить ему снова, пока не получите все, что хотите.Вы можете сделать что-то вроде этого:

long targetArray[ARRAY_LEN]; 

char *buffer = (char*)targetArray; 
size_t remaining = sizeof(long) * ARRAY_LEN; 
while (remaining) { 
    ssize_t recvd = read(socketFD, buffer, remaining); 
    // TODO: check for read errors etc here... 
    remaining -= recvd; 
    buffer += recvd; 
} 
+0

Это звучит как самый логичный ответ. Я проверю это сейчас. –

+0

Хмм, результат чтения (...), похоже, не коррелирует с фактическим количеством действительных прочитанных элементов int. Кажется, что он меняется каждый раз, когда я читаю (иногда его ~ 65593 и другие его ~ 49923). Несмотря на это, я буду читать в кусках, как я это делал ранее. –

+0

Эта строка, похоже, не компилируется: buffer + = recvd; Я получаю ошибку: указатель типа 'void *', используемый в арифметике –

5

Является следующее:

for (int i = 0; sourceArrayPointer < i; i++) 

Вы сравниваете яблоки и апельсины (считывающие указатели и целые числа). Этот цикл не выполняется, поскольку указатель на массив long s is> 0 (наиболее часто). Итак, в конце приема вы читаете от унифицированного массива, в результате которого пропускаются те неправильные числа).

Он предпочел бы быть:

for (int i = 0; i < ARRAY_LEN; i++) 
+0

Должно быть, опечатка. Как скомпилировать первую строку? (или мой C слишком ржавый) – erikkallen

+0

@erikkallen: Вот почему в первой строке есть вопрос. – dirkgently

+0

На архитектурах Intel, к которым мы привыкли, как «int», так и «long *» (указатель на длинный) являются 32-битными значениями. «Int» - 32 бита, а «указатель на длинный» - это адрес памяти, который имеет ширину в 32 бита. Компилятор позволит вам выполнить сравнение (но, вероятно, это предупреждение) – poundifdef

0

Не относится к этому вопросу, но вы также должны заботиться о endianness платформ, если вы хотите использовать TCP на разных платформах.

Проще использовать некоторую сетевую библиотеку, такую ​​как curl или ACE, если это опция (дополнительно вы узнаете гораздо больше на более высоком уровне, например, шаблоны проектирования).

0

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

0

Я вижу здесь несколько проблем. Во-первых, так я переписываю ваш код отправки, насколько я его понимаю. Я предполагаю, что getSourceArray всегда возвращает действительный указатель на статический или malloced буфер размером ARRAY_LEN. Я также предполагаю, что вам больше не нужен sourceArrayPointer в коде.

#define ARRAY_LEN 262144 

long *sourceArrayPointer = getSourceArray(); 

long sourceArray[ARRAY_LEN]; 
long *sourceArrayIdx = sourceArray; 

for (; sourceArrayIdx < sourceArray+ARRAY_LEN ;) 
    sourceArrayIdx++ = sourceArrayPointer++; 

int result = send(clientSocketFD, sourceArray, sizeof(long) * ARRAY_LEN); 
if (result < sizeof(long) * ARRAY_LEN) 
    printf("send returned %d\n", result); 

Глядя на исходном коде, я предполагаю, что ваш цикл был перепутались и никогда не выполняет в результате вы отправки любой случайный хлам, случается в sourceArray памяти указывает. В основном ваше состояние

sourceArrayPointer < i; 

в значительной степени гарантированно сбой в первый раз.

+0

Опять же, в отношении вашего последнего момента, это была опечатка, эта ошибка не существует в исходном коде. Спасибо, в любом случае. –