Send structure over socket with correct complement and content in C

I have several structures defined for sending through different operating systems (tcp networks). Defined Structures:

struct Struct1 { uint32_t num; char str[10]; char str2[10];} struct Struct2 { uint16_t num; char str[10];} typedef Struct1 a; typedef Struct2 b; 

Data is stored in a text file. The data format is as follows:

  • 123
  • Pie
  • Glaze

Struct1 a is saved as 3 separate parameters. However, struct2 is two separate parameters, with the 2nd and 3rd lines being stored on char str []. The problem is that when I write to the server over several networks, the data is received incorrectly. There are many spaces that share various parameters in structures. How can I ensure the correct sending and filling when I write to the server? How to store data (dynamic buffer or fixed buffer)?

Example write: write (fd, & a, sizeof (typedef struct a)); Is it correct?

Error getting side output for struct2:

  • 123 (,)
  • 0 (, Pie)
  • 0 (Corust,)

Correct exit

123 (pie, crust)

+4
source share
4 answers

write(fd,&a, sizeof(a)); incorrect at least not portable, as the C compiler can inject padding between elements to ensure proper alignment. sizeof(typedef struct a) doesn't even make sense.

How you should send data depends on the characteristics of your protocol. In particular, protocols define a variety of ways to send strings. As a rule, it is most safe to send struct elements individually; either a few calls to write, or writev(2) . For example, to send

 struct { uint32_t a; uint16_t b; } foo; 

over a network where foo.a and foo.b already have the correct endianness, you would do something like:

 struct iovec v[2]; v[0].iov_base = &foo.a; v[0].iov_len = sizeof(uint32_t); v[1].iov_base = &foo.b; v[1].iov_len = sizeof(uint16_t); writev(fp, v, 2); 
+10
source

Sending structures over the network is complicated. The following problems are possible:

  • The endiannes byte specifies integers.
  • Filling entered by your compiler.
  • Parsing strings (i.e. detecting line boundaries).

If performance is not your goal, I would suggest creating encoders and decoders for each sent and received structure (ASN.1, XML or custom). If performance is really required, you can still use structures and solve (1) fixing the finiteness (i.e. Network byte order) and ensuring that your integers are stored as such in these structures, and (2) by fixing the compiler and using pragmas or attributes to provide a “packaged” structure.

For example, Gcc uses the attribute (( packaged )):

 struct mystruct { uint32_t a; uint16_t b; unsigned char text[24]; } __attribute__((__packed__)); 

(3) to solve is not easy. Using zero-terminated strings in a network protocol and depending on your presence, your code will be vulnerable to multiple attacks. If you need to use strings, I would use the correct encoding method, such as the one suggested above.

+3
source

An easy way would be to write two functions for each structure: one for converting from a text representation to a structure and one for converting a structure back to text. Then you simply send the text over the network, and on the receiving side, convert it to your structures. Thus, judgment does not matter.

+1
source

There are conversion functions that provide binary integer portability over the network. Use htons, htonl, ntohs and ntohl to convert 16 and 32 bit integers from the host to network byte order and vice versa.

+1
source

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


All Articles