C sockets send / recv buffer type

I work with unix sockets and I can send () and recv () data when my buffer is of type char (i.e. sends and receives strings). I used the Beej manual for sockets, and the examples were used for send / return strings.

Now I want to send / recv data of different types in one message.
For example, let's say in one message, I want to send an integer, string, double and float. How can I do it? In particular, what type should a message buffer have?

Prototypes for sending and returning:

int recv (int socket, void *buffer, size_t size, int flags) int send (int socket, void *buffer, size_t size, int flags) 

I don't have much experience with C / C ++ and pointers, so this is probably a question about the noob.

If someone can lead me in the right direction, I would really appreciate it. Thanks

+4
source share
5 answers

If you plan on sending huge amounts of data (many kilobytes) and often (several packets per second), I would suggest that you translate your data into strings (also called “data serialization”) and transfer it that way. It has several advantages:

  • It is portable - it works regardless of the size of the int or float or double - or the indentation between the fields is in the structure.
  • Easy to debug (you can just look at the data and say whether it is correct or not)
  • It doesn't matter what byte order for sending / receiving machines.

Sending binary data, on the other hand, is difficult, because you need to worry about the individual sizes of the data fields and their internal representation (the byte order as double displayed in binary format, filling data fields inside structures cannot transmit pointers, etc. and etc.). The only advantage is that binary data is a bit more compact. But this only matters if you have a lot of kilobytes and / or send a lot of packets every second.

+2
source

The best way would be to encapsulate the information you want to convey in the structure. Then pass the address and length of the structure. Note that buffer is void* , so you can pass the address of the structure containing your information.

Here is a small fragment of the struct that I used for safe copying, such as a tool,

 struct message { size_t total_len; size_t filename_len; char *filename; size_t text_len; char *text; char *iv; char *salt; unsigned char *hmac; }; 

Then serialize message in <<24>, and then write to socket

 bool send_message(const struct message *msg, const char *ip, const char *port) { ... connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); // Serialize to file serialize(msg, "temp"); // Transfer the file over the network fp = fopen("temp", "rb"); while((n = fread(buffer, 1, MAX_BUF_LEN, fp)) != 0) { write(sockfd, buffer, n); } fclose(fp); remove("temp"); close(sockfd); } 

As suggested by @vitaut, you can use the library for serialize , I implemented it as a learning experience.

+2
source

You need to serialize the objects on the sender side and deserialize on the receiver side. There are several libraries for C ++, such as Boost Serialization , or if you feel like you are reinventing the wheel, you can always fold your own.

+2
source

Well, to answer the question asked ("How to send structs?"), You simply send a pointer to the structure.

 struct foo { int a; int b; }; struct foo s; sa = 10; sb = 20; send(socket,&s,sizeof(s),0); 

It's really that simple. Now the other side should be the same (i.e., the structure laid out in memory in system A should correspond to the structure set out in system B). It is best to use more specific types and some functions to properly organize the data:

 #ifndef __GNUC__ # define __attribute__(x) #endif #ifdef __SunOS # pragma pack(1) #endif struct foo { uint32_t a; uint32_t b; } __attribute__((packed)); #ifdef __SunOS # pragma pack() #endif struct foo s /* to send */ sa = htonl(10); sb = htonl(20); send(socket,&s,sizeof(s),0); /* to receive */ recv(socket,&s,sizeof(s),0); sa = ntohl(sa); sb = ntohl(sb); 

You can see that it begins to quickly get system-specific when you want to “transfer” binary data over the network, so people say that they convert to text or, quite possibly, use the already written serialization library.

+2
source

It depends on how portable it should be.

The easiest way is to convert everything to ASCII, separated by a comma or semicolon, and parse it again on the receiving side.

You can also convert it to network byte order and send it as binary.

0
source

All Articles