C++ Byte order in socket programming - c++

In C++ we send data using socket on the network. I am aware that we need to use htons() , ntohs() function to maintain byte order big endian and little endian.
support we have following data to be sent
int roll;
int id;
char name[100];
This can also be wrapped into struct.
My confusion here is, for roll and id, we can use htons() function. But for the string name, what should and how should we do it? Do we need to use any such function? will it work on every machine like mac, intel and other network?
I want to send all three fields in one packet.

You'd use htonl for int, not htons.
The name doesn't need to be reordered, since the bytes of the array correspond directly to bytes on the network.
The issue of byte-order only arises with words larger than a byte, since different architectures choose different ends at which to place the least-significant byte.

For char arrays this conversion is not necessary since they do not have a network byte order but are sequentially transmitted. The reason that ntohs and htons exist, is that some data types consist of lesser and more significant bits, which are interpreted differently on different architectures. This is not the case in strings.

To add to helpful comments here - if your structs get much more complex you could be better off considering a serialization library like Boost.Serialization or Google Protocol Buffers, which handle endianness for you under the covers.
When encoding the string, make sure you send a length (probably a short handled using htons) before the string itself, don't just send 100 chars every time.

Related

What is the data type of content sent over socket?

When using Berkeley socket api, what is the data type of content that is sent over the read/send or write/recv calls? For example -
char *msg = "Our Message!";
int len, bytes_sent;
len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);
in this code, we are using char type, but are we limited to just char type since send/write/sendto usually take void * type. I've also seen arguments like if we send some int, it might actually be stored in little endian/big endian causing problems b/w source/dest if their endianess don't match. Then why doesn't char type suffers from this problem too?
Also different languages like C and C++ have different size of char too, then why isn't this a problem? If socket doesn't care any type and just sees the content as buffer, why don't we see random corruption of data when different tcp servers/clients are written in different languages and communicate with each other?
In short, what values(type) can I send safely through sockets?
You cannot safely send anything through a raw socket and expect the receiver to make sense of it. For example, the sending process might be on a machine where the character encoding is EBCDIC, and the receiving process might be on a machine where the character encoding was ASCII. It's up to the processes to either negotiate a protocol to sort this out, or to simply say in their specifications "We are using ASCII (or whatever)".
Once you have got the character encodings worked out, transmit the data in text is my advice. This avoids all endian problems, and is easier to debug and log.
The simplest answer is that the data is an uninterpreted stream of octets, that is to say 8-bit bytes. Any interepretation of it is done by the sender and receiver, and they better agree. You certainly need to take both the size and endianness of integers into account, and compiler alignment and padding rules too. This is why for example you should not use C structs as network protocols.

How do I serialize a struct of 8bit integers for socket programming?

I have a struct that has 5 unsigned 8 bit integers that mimics a frame with 5 packets. After researching, I know need to serialize the data, field by field, especially since I am sending from a Windows machine to a Linux machine and back.
here is my struct:
typedef struct pressure{
UINT8 a;
UINT8 b;
UINT8 c;
UINT8 d;
UINT8 e;
}pressure;
The issue is I cant use htons() since my members must be 8 bits. How do I manually serialize this? It would be greatly appreciated if you could provide a short code sample that shows how to serialize and what to pass to send().
You can either write each individual byte using ostream::put, or - if you've ensured they're contiguous in memory in pressure (which will be done on every compiler I've ever used without you doing anything actively) - write the lot of them using ostream::write, as in:
my_ostream.write(static_cast<const char*>(&my_pressure.a), 5);
That said, consider keeping the values in an array so you're guaranteed they're contiguous in memory.
You don't need htonX / ntohX etc. - they're for normalising/denormalising multi-byte integer representations, which you don't have here.
Just write it if you are sending from an Intel x86 based machine to another Intel x86 machine (which most linuxes are).
If however you plan to send it to a machine based on another processor the safest thing is to just send ASCI characters so something like:
char[] buffer = sprintf("|%03d|%03d|%03d|%03d|%03d|",a,b,c,d,e);
Would give you a fixed length string readable by any machine. Its a good idea to have some sort of field separator (the "|" in this case) to help the receiver verify the string has not been garbled by an unreliable network.

possible to use htonl on a string

I want to send a string over a socket, but have to worry about endianness. The only way I know how to fix this is using htonl, but to my knowledge that only works on strings. How can I send a string over a socket?
I don't believe you have to do anything for strings (I'm assuming char* UTF-8) since characters are only one byte in length, so you do not have to worry about endianness. You only need to worry about byte ordering if your data is more than 1 byte in length (e.g. short, long, etc.).
Here's a wiki article explaining this topic in much greater detail.

Send array of integers (winsock)

I have a client/server program I'm writing, I need to send information from client to server using the function send(SOCKET s, const char *buf, int len, int flags);
but apparently this function is made to said a string, array of characters, but what I'm sending is encrypter message and the characters values large and character type isn't enough.
is there another function that allows me to do so ? I looked the reference in microsoft website but I didn't get the other functions.
if there's another function I hope you can show me how or give me hints, or if there's another way to do then so be it.
Notes: I'm working with C++ under Windows 8, using Borland 6
This might be tricky to explain.
Your issue isn't in the function you're using, but in the concept you're trying to apply.
First of all, if your data is intended to be transmitted through network, you must assume that the destination endpoint endianness may differ from the transmitting endpoint.
With that in mind, it's advisable to convert the eligible data types prone to endianness interpretation to network byte order before transmitting any data. Take a look at the htons(), htonl(), ntohs() and ntohl() functions.
As you must deal with known data sizes, instead of declaring your array as int[], you should declare it through a stdint.h type, such as int16_t, int32_t, uint16_t, etc.
So, lets assume you've the following:
uint32_t a[4] = { 1, 2, 3, 4 };
If you want to transmit this array in a portable way, you should first convert its contents to network byte order:
uint32_t a_converted[4];
for (int i = 0; i < sizeof(a); i ++)
a_converted[i] = htonl(a[i]);
Now, if you want to transmit this array, you can do it using:
send(s, (char *) a_converted, sizeof(a_converted), flags);
Just remember that the code for receiving this data, should convert it from network byte order to host byte order, using, in this case, the ntohl() for each element received.
Hope this gives you some clues for further research.
Well doodleboodle, guess what, if you read the TCP RFC, you might under stand that the TCP protocol only transfers OCTET STREAMS and, if you need to transfer anything more complex than one byte, you need a protocol on top of TCP that defines your Application Protocol Unit message type.
send(SOCKET s, const char *buf, int len, int flags); is basically the way to do it.
It uses binary data in bytes to send the data. So if you want to send a complex structure/object, you'll need to serialize it to a byte array first.
In your case with the integers it's quite simple: just convert the integer array to a byte array. (keep track of the length though).
Of course it's more appropriate to build an abstraction layer on top of your TCP layer so it's easier to send/receive different kinds of data.

Combine multiple variables to send as a udp packet

I need to send a packet of data over a UDP connection in C++. The first message I need to send is built up of two 32 bit integers and a 64 bit integer. What is the best way to combine multiple variable types into one block of data ready for sending over a UDP connection?
It depends on the requirements for your network. Do you care about endianness? If you do, you should use not just any serialisatioin, but a safe one in regards to endianness.
Generally, each class/struct sendable through the network should have special methods or overloaded operators to stream them in and out. Ultimately you'll have to use macros/functions like hton/ntoh for streaming primitive types eg int, int64, float, double etc.
Upd: also if your network endpoint applications run on different platforms/compilers, you may have different sizes of int, long, short etc. So when serialising, you'll have to convert your integers to some predefined types with sizes guaranteed to be the same on all supported platforms.
I wrote a DNS resolver by hand in C, and structs is indeed the way I did it. Use bit fields to specify sizes of each piece. More about bit fields: http://msdn.microsoft.com/en-us/library/ewwyfdbe.aspx
Make sure to use hton/ntoh to take care of byte order. More information here; http://www.beej.us/guide/bgnet/output/html/multipage/htonsman.html
In fact, peruse beej's guide -- mucho useful information there!