Reputation: 157
I'm trying to communicate via socket between windows (client) and linux (server). I can start the communication, but when I send data, problems arise. The main problem is that I try to send 2 data double and 1 data ulong but when I read them on the server (Linux) I can not read a correct value. If I send, for example, double1 = 1.5, I receive 0.0000 on the server. Then if I send a double1 = 550.0 I receive on the server -12382718421... (trash)
I have tried to use htonl, ntohl, etc. It does not work I have tried to reorder the bytes of the frame I send from the client, that is, send B0 ... B7 instead of B7 ... B0 ... It does not work. I have been looking for information about it but I can not find anything, except that socket communication between different operating systems is possible, therefore I know there is a solution.
My questions are:
1 - Does htonl and nthol only work with integers? Can I use those conversions for float data?
2 - What is the byte order of a frame in linux and windows?
3 - I know that the sendto () function returns the number of bytes that are being sent. What I send are 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes. But the function returns 24Bytes, how can this be? Is it due to UDP protocol headers or is it additional information that includes Windows?
Thanks all.
PD1: The programming of the sockets is correct.
PD2: Between Linux-Linux I have no problem and I can send data correctly.
Upvotes: 0
Views: 641
Reputation: 32596
Does htonl and nthol only work with integers? Can I use those conversions for float data
To manage float you can for instance use an union to transform float in a uint32_t
and vice versa, or use a cast of a pointer of float to a pointer of uint32_t
and vice versa, of course do not cast a float to uint32_t
and reverse
But you seem to work an double rather than float, in that case you need to use htobe64/htole64/be64toh/le64toh (endian.h
), if they are not defined under Windows decide the order or the bytes in your packet and define the conversion by yourself
What is the byte order of a frame in linux and windows
The order is only dependent on the CPU, not on the OS
I know that the sendto () function returns the number of bytes that are being sent. What I send are 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes. But the function returns 24Bytes, how can this be? Is it due to UDP protocol headers or is it additional information that includes Windows?
You only access to the payload, all the header/footer/etc are hidden to you
Probably you send a struct rather than making yourself the packet to send, in that case the compilers just do not follow the same padding or the size of a long is 32b on one and 64b on the other ?
Do not send a struct, copy the numbers in a vector of bytes managing the endian, and extract them in the same way
For instance doing all by hand, an unsigned long is read/write on 8 bytes to allow to be compatible even if they have 64b on a host and less on the other :
#include <string.h>
void encDec32(char * a, char * b)
{
const int e = 1;
if (*((char *) &e)) {
memcpy(a, b, 4);
}
else {
a[0] = b[3];
a[1] = b[2];
a[2] = b[1];
a[3] = b[0];
}
}
void encDec64(char * a, char * b)
{
const int e = 1;
if (*((char *) &e)) {
memcpy(a, b, 8);
}
else {
a[0] = b[7];
a[1] = b[6];
a[2] = b[5];
a[3] = b[4];
a[4] = b[3];
a[5] = b[2];
a[6] = b[1];
a[7] = b[0];
}
}
void encodeU32(char ** buffer, uint32_t v)
{
encDec32(*buffer, (char *) &v);
*buffer += 4;
}
void encodeU64(char ** buffer, uint64_t v)
{
encDec64(*buffer, (char *) &v);
*buffer += 8;
}
void encodeFloat(char ** buffer, float v)
{
encDec32(*buffer, (char *) &v);
*buffer += 4;
}
void encodeDouble(char ** buffer, double v)
{
encDec64(*buffer, (char *) &v);
*buffer += 8;
}
void encodeUlong(char ** buffer, unsigned long v)
{
/* force on 8 bytes to be compatible with CPU 32 and 64 */
encodeU64(buffer, (uint64_t) v);
}
uint32_t decodeU32(char ** buffer)
{
uint32_t v;
encDec32((char *) &v, *buffer);
*buffer += 4;
return v;
}
uint64_t decodeU64(char ** buffer)
{
uint64_t v;
encDec64((char *) &v, *buffer);
*buffer += 8;
return v;
}
float decodeFloat(char ** buffer)
{
float v;
encDec32((char *) &v, *buffer);
*buffer += 4;
return v;
}
float decodeDouble(char ** buffer)
{
double v;
encDec64((char *) &v, *buffer);
*buffer += 8;
return v;
}
unsigned long decodeUlong(char ** buffer)
{
/* force on 8 bytes to be compatible with CPU 32 and 64 */
return (unsigned long) decodeU64(buffer);
}
/* for a struct */
typedef struct S {
unsigned long u; /* may be on 32 or 64 and not the same size on Linuw and Windows */
double d1;
double d2;
} S;
/* b is the block to send, it must be enough long */
/* return the number of bytes to send in a block through UDP */
size_t encodeS(char * b, S * s)
{
char * b0 = b;
encodeUlong(&b, s->u);
encodeDouble(&b, s->d1);
encodeDouble(&b, s->d2);
return b - b0;
}
/* b is the block read through UDP */
void decodeS(char * b, S * s)
{
s->u = decodeUlong(&b);
s->d1 = decodeDouble(&b);
s->d2 = decodeDouble(&b);
}
Upvotes: 0
Reputation: 67743
1 - Does htonl and ntohl only work with integers? Can I use those conversions for float data?
Those functions are only defined for integers. You need to know the format each platform stores doubles in (including endianness) to decide whether you need to re-order the bytes or perform some other conversion.
2 - What is the byte order of a frame in linux and windows?
The question doesn't make sense. You decided what to put in this packet, so the byte order is just whatever you sent.
Traditionally wire formats are often big-endian, but lots of modern formats are little-endian on the grounds that most peers will be using x86.
For your specific case, the fact that you're receiving on Linux is less relevant than the architecture Linux is running on. You haven't mentioned that, but assuming x86_64, the endianness and double
format are probably the same as for your sending code.
NB. You should probably use the fixed-size types from <stdint.h>
, for example uint64_t
instead of unsigned long
(assuming that is what you intended). Types like long
specifically can be different sizes in different ABIs even on the same platform.
3 - I know that the sendto () function returns the number of bytes that are being sent. What I send are 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes. But the function returns 24Bytes, how can this be? Is it due to UDP protocol headers or is it additional information that includes Windows?
Show your code. The return value from sendto
shouldn't be larger than the length argument you passed, so maybe that value isn't what you thought.
The extra length definitely isn't IP or UDP headers, which are longer than 4 bytes anyway.
I have tried to use htonl, ntohl, etc. It does not work
Stop flailing around trying different transforms in the hope one works.
Print a hex dump of your buffer before sending. Print a hex dump of your buffer after receipt. Fill out the structure you expected to see in the receiver and hex dump that, so you can see the difference.
Upvotes: 2