When sending an array of int over TCP, why are onl

2019-07-29 12:10发布

问题:

Following my previous question (Why do I get weird results when reading an array of integers from a TCP socket?), I have come up with the following code, which seems to work, sort of. The code sample works well with a small number of array elements, but once it becomes large, the data is corrupt toward the end.

This is the code to send the array of int over 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);

And this is the code to receive the array of int:

#define ARRAY_LEN 262144

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

The first few numbers are fine, but further down the array the numbers start going completely different. At the end, when the numbers should look like this:

0
0
0
0
0
0
0
0
0
0

But they actually come out as this?

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

Is this because I'm using the wrong send/recieve size?

回答1:

The call to read(..., len) doesn't read len bytes from the socket, it reads a maximum of len bytes. Your array is rather big and it will be split over many TCP/IP packets, so your call to read probably returns just a part of the array while the rest is still "in transit". read() returns how many bytes it received, so you should call it again until you received everything you want. You could do something like this:

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;
}


回答2:

Is the following ok?

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

You are comparing apples and oranges (read pointers and integers). This loop doesnot get executed since the pointer to array of longs is > 0 (most always). So, in the receiving end, you are reading off of from an unitialized array which results in those incorrect numbers being passed around).

It'd rather be:

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


回答3:

Use functions from <net/hton.h>

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



回答4:

Not related to this question, but you also need to take care of endianness of platforms if you want to use TCP over different platforms.

It is much simpler to use some networking library like curl or ACE, if that is an option (additionally you learn a lot more at higher level like design patterns).



回答5:

There is nothing to guarantee how TCP will packet up the data you send to a stream - it only guarantees that it will end up in the correct order at the application level. So you need to check the value of result, and keep on reading until you have read the right number of bytes. Otherwise you won't have read the whole of the data. You're making this more difficult for yourself using a long array rather than a byte array - the data may be send in any number of chunks, which may not be aligned to long boundaries.



回答6:

I see a number of problem's here. First, this is how I would rewrite your send code as I understand it. I assume getSourceArray always returns a valid pointer to a static or malloced buffer of size ARRAY_LEN. I'm also assuming you don't need sourceArrayPointer later in the code.

#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);

Looking at your original code I'm guessing that your for loop was messed up and never executing resulting in you sending whatever random junk happens to be in the memory sourceArray points to. Basically your condition

sourceArrayPointer < i;

is pretty much guaranteed to fail the first time through.



标签: c sockets tcp