tags:

views:

1722

answers:

6

I'm lead to believe that write() can only send data buffers of byte (i.e. signed char), so how do I send an array of long integers using the C write() function in the sys/socket.h library?

Obviously I can't just cast or convert long to char, as any numbers over 127 would be malformed.

I took a look at the question, how to decompose integer array to a byte array (pixel codings), but couldn't understand it - please could someone dumb it down a little if this is what I'm looking for?

Follow up question:

Why do I get weird results when reading an array of integers from a TCP socket?

+8  A: 

the prototype for write is:

ssize_t write(int fd, const void *buf, size_t count);

so while it writes in unites of bytes, it can take a pointer of any type. Passing an int* will be no problem at all.

EDIT:

I would however, recomend that you also send the amount of integers you plan to send first so the reciever knows how much to read. Something like this (error checking omitted for brevity):

int x[10] = { ... };
int count = 10;
write(sock, &count, sizeof(count));
write(sock, x, sizeof(x));

NOTE: if the array is from dynamic memory (like you malloced it), you cannot use sizeof on it. In this case count would be equal to "sizeof(int) * element_count"

EDIT:

As Brian Mitchell noted, you will likely need to be careful of endian issues as well. This is the case when sending any multibyte value (as in the count I recommended as well as each element of the array). This is done with the: htons/htonl and ntohs/ntohl functions.

Evan Teran
Should I pass an array of pointers, or a pointer to an array?
nbolton
Evan Teran
+2  A: 

Yes, you can just cast a pointer to your buffer to a pointer to char, and call write() with that. Casting a pointer to a different type in C doesn't affect the contents of the memory being pointed to -- all it does is indicate the programmer's intention that the contents of memory at that address be interpreted in a different way.

Just make sure that you supply write() with the correct size in bytes of your array -- that would be the number of elements times sizeof (long) in your case.

j_random_hacker
+5  A: 

Write can do what you want it to, but there's some things to be aware of:

1: You may get a partial write that's not on an int boundary, so you have to be prepared to handle that situation

2: If the code needs to be portable, you should convert your array to a specific endianess, or encode the endianess in the message.

Brian Mitchell
A: 

The simplest way to send a single int (assuming 4-byte ints) is :

int tmp = htonl(myInt);
write(socket, &tmp, 4);

where htonl is a function that converts the int to network byte order. (Similarly,. when you read from the socket, the function ntohl can be used to convert back to host byte order.)

For an array of ints, you would first want to send the count of array members as an int (in network byte order), then send the int values.

Dan Breslau
instead of assuming a 4-byte int, just use sizeof(tmp)...
Evan Teran
You *have* to fix the size of the int, because you cannot assume that the receiver is going to have the same sizeof(int).
Dan Breslau
if you both don't have the same size int, it will be broken regardless. Either you send too much or too little relative to the receiver... I suppose this is why uint32_t would be much more preferable.
Evan Teran
You're right that using 'int' is broken if the code is running on different archictectures. Instead of writing "assuming 4-byte ints", I should have said "different code is needed to make this work independent of the CPU."
Dan Breslau
A: 

I think what you need to come up with here is a protocol.

Suppose your integer array is:

100, 99, 98, 97

Instead of writing the ints directly to the buffer, I would "serialize" the array by turning it into a string representation. The string might be:

"100,99,98,97"

That's what would be sent over the wire. On the receiving end, you'd split the string by the commas and build the array back up.

This is more standardised, is human readable, and means people don't have to think about hi/lo byte orders and other silly things.

// Sarcasm

If you were working in .NET or Java, you'd probably encode it in XML, like this:

<ArrayOfInt><Int>100</Int><Int>99</Int><Int>98</Int><Int>97</Int></ArrayOfInt>

:)

Paul Stovell
Yeah, I did that originally (as I'm used to C#), but there was too much overhead, as the size of the array is very large.
nbolton
+1  A: 

It would be better to have serialize/de-serialize functionality in your client /server program.

Whenever you want to send data, serialize the data into a byte buffer and send it over TCP with byte count.

When receiving data, de-serialize the data from buffer to your own interpretation .

You can interpret byte buffer in any form as you like. It can contain basic data type, objects etc.

Just make sure to take care of endianess and also alignment stuff.

Alien01