How can I transfer a C structure through a network socket?

Suppose I have a C structure defined as follows:

typedef struct servData { char max_word[MAX_WORD]; char min_word[MAX_WORD]; int word_count ; } servSendData ; 

where "MAX_WORD" can be any value. Now, if I have an instance of this structure:

 servSendData myData ; 

And if I fill out this instance and then send it over the network, will there be any portability problems here, given that I want my server as well as the client to work on a 64-bit system or 32-bit system.

I am going to send and receive data as follows:

 //server side strcpy(myData.max_word, "some large word") ; strcpy(myData.min_word, "small") ; myData.word_count=100 ; send(sockFd, (char*)&myData, sizeof(myData); //client side recv(sockFd, (char*)&myData, sizeof(myData); printf("large word is %s\n", myData.max_word) ; printf("small word is %s\n", myData.min_word) ; printf("total words is %d\n", myData.word_count) ; 
+6
source share
5 answers

According to others, there are real problems when copying a C structure between different machines with different compilers / word size / and endian structure. One common way to solve this problem is to convert your data into a machine-independent format, transfer it over the network, and then convert it back to the recipient structure. This is such a common requirement that several technologies already exist for this - two of which spring, in my opinion, are gsoap and rpcgen , although there may be many other options.

I mainly used gsoap, and after you finish the initial learning curve, you can develop reliable solutions that scale well (with multiple threads) and that handle both network and data transfers for you.

If you do not want to go along this route, then the safe approach is to write procedures that convert your data to a standard string format (if you have problems with Unicode, you will need to take this into account as well), and then send this via network.

+1
source

Yes, there will definitely be problems with portability.

Coordination of structural elements can be different even among different compilers on the same platform, not to mention different platforms. And that’s all, assuming that sizeof(int) same for all of them (although provided, usually this is --- but do you really want to rely on "usually" and hope for the best?).

This is done even if MAX_WORD on both computers (I assume they are from here, and if not, then you have problems here).

What you need to do is send (and receive) each field separately. There is also a problem with sizeof(int) and endianness, so I added a htonl() call to convert from the system to the network byte order (the reverse function is ntohl() ). They both return uint32_t , which has a fixed, known size.

 send(sockFd, myData.max_word, sizeof(myData.max_word)); // or just MAX_WORD send(sockFd, myData.min_word, sizeof(myData.min_word)); uint32_t count = htonl(myData.word_count); // convert to network byte order send(sockFd, &count, sizeof(count)); // error handling! if((ret = recv(sockFd, myData.max_word, sizeof(myData.max_word))) != sizeof(myData.max_word)) { // handle error or read more data } ... // and so on // remember to convert back from network byte order on recv! // also keep in mind the third field is now `uint32_t`, and not `int` in the stream 
+5
source

You need to take care of the content.

Can you use the hton () or ntoh () functions to convert between small and large endian.

+1
source

You can use the packaging structure . With most C compilers, you can apply a specific alignment structure. It is sometimes used for what you need - to transfer a struct over a network.

Please note that this still leaves content issues, so this is not a universal solution.

0
source

If you are not writing firmware, sending data between applications without proper serialization is rarely a good idea.

The same goes for using raw sockets, which is not very convenient, and is a bit like "reinvent the wheel."

Many libraries can help you with both! Of course, you do not need to use them, but reading their documentation and understanding how they work will help you make the best choice. Things that you have not planned yet may appear out of the box (for example, what happens when you want to update your system and the message format changes?)

For serialization, read these general-purpose formats:

  • Human reading: JSON, XML, YAML, others ...
  • Binary: Protobuf , TPL , Avro , BSON, MessagePack and many others

To abstract the socket, find

  • Boost asio
  • ZeroMQ
  • nanomsg
  • A lot others
0
source

Source: https://habr.com/ru/post/982324/


All Articles