Reputation: 1615
I'm working with unix sockets, and I can send() and recv() data when my buffer is of type char (ie. sending and receiving strings). I used Beej's guide to sockets, and the examples used were for send'ing/recv'ing strings.
Now I want to send/recv data of different types in one message.
For example, say in one message I want to send an integer, a string, a double and a float.
How should I go about doing this? More specifically, of what type should my message 'buffer' be?
The prototypes for send and recv:
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 too much experience with C/C++ and pointers, so this is probably a noob question.
If anyone can guide me in the right direction, I'd really appreciate it. Thanks
Upvotes: 4
Views: 8836
Reputation: 416
Well, to answer the question as asked ("How do I send structs?"), you just send a pointer to the structure.
struct foo
{
int a;
int b;
};
struct foo s;
s.a = 10;
s.b = 20;
send(socket,&s,sizeof(s),0);
It really is that easy. Now, the other side has to be the same (that is, the structure as laid out in memory on system A must match the structure as laid out on system B). A better way is to use more specific types and some functions to order the data properly:
#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 */
s.a = htonl(10);
s.b = htonl(20);
send(socket,&s,sizeof(s),0);
/* to receive */
recv(socket,&s,sizeof(s),0);
s.a = ntohl(s.a);
s.b = ntohl(s.b);
You can see it starts to get system specific rather quick when you want to "portably" send binary data across a network, which is why people are saying to convert to text, or quite possibly use a serialization library that's already written.
Upvotes: 2
Reputation: 8991
The best way would be to encapsulate the information that you want to pass in a structure. And then pass the address and length of the structure. Note that buffer
is a void*
so this allows you to pass the address of the structure containing your information.
Here is a small snippet of the struct
I had used for a secure copy like 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 in your send_message()
serialize the message
and then write
to the 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 a library to serialize
, I had implemented it as a learning experience.
Upvotes: 2
Reputation: 129314
Unless you are planning to send vast amounts of data (many kilobytes) and often (several packets per second), I would suggest that you translate your data to strings (aka "serialize the data") and pass it that way. It has several benefits:
int
or float
or double
is - or what the padding between fields are in the structure. Sending binary data, on the other hand is complex, because you need to worry about the individual sizes of data fields and their internal representation (byte order, how a double
is represnted in binary, padding of data fields within structures, can't pass pointers, etc, etc). The only benefit is that binary data is a little more compact. But that only matters if you have many kilobytes and/or send lots of packets every second.
Upvotes: 2
Reputation: 74018
That depends on how portable this must be.
The easiest way is to convert everything to ASCII separated by 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.
Upvotes: 0
Reputation: 55524
You need to serialize objects on the sender side and deserialize on the receiver side. There is a number of libraries for that in C++, for example Boost Serialization or if you feel like reinventing the wheel you can always roll your own.
Upvotes: 2