Почему при отправке массива int через TCP правильно только первое значение? - PullRequest
1 голос
/ 23 марта 2009

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

Это код для отправки массива int по 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

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

Ответы [ 6 ]

7 голосов
/ 23 марта 2009

Вызов read(..., len) не читает len байтов из сокета, он читает максимум len байтов. Ваш массив довольно большой, и он будет разделен на множество пакетов TCP / IP, поэтому ваш вызов read, вероятно, вернет только часть массива, в то время как остальная часть все еще «в пути». 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;
}
5 голосов
/ 23 марта 2009

Хорошо ли следующее?

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

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

Скорее всего, будет:

for (int i = 0; i < ARRAY_LEN; i++)
1 голос
/ 23 марта 2009

Использовать функции от <net/hton.h>

http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking

0 голосов
/ 23 марта 2009

Я вижу ряд проблем здесь. Во-первых, я бы переписал ваш код отправки, как я его понимаю. Я предполагаю, что getSourceArray всегда возвращает действительный указатель на статический или неправильный буфер размером 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);

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

sourceArrayPointer < i;

гарантированно потерпит неудачу с первого раза.

0 голосов
/ 23 марта 2009

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

0 голосов
/ 23 марта 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...