Suppose I have two independent Linux processes, one of which must update hashtable in another. I need to send two C structures at a time (to avoid transactionality issues):
struct key
{
uint32_t id;
};
struct value
{
uint8_t arr[16];
uint32_t var;
uint32_t var2;
};
Is there any best-practise way of implementing this?
I see two main options (both with iovec
):
Send two structs through 2 iovec elements:
struct key key; key.id= 123; struct value value; memset(value.arr, 0, sizeof(value.arr)); value.var= 456; value.var2= 101; struct iovec iov[2]; iov[0].iov_base = &key; iov[0].iov_len = sizeof(key); iov[1].iov_base = &value; iov[1].iov_len = sizeof(value); struct msghdr msg; ... if (sendmsg(sockfd, &msg, 0) < 0) { ...
This method has advantage that API (key-value) is strictly regulated with common header file, where
struct key
andstruct value
are declarated.
The disadvantage is that this method requires struct packing (pragma pack) because we can't rely on the fact that padding/gaps will be the same in these two independent binaries (only the struct members order is guaranteed by C standard). Packing can decrease performance because of unaligned access so it will produce two struct definitions - one for transport (packet), another for internal usage.Send every struct's element as iovec element
struct key key; key.id= 123; struct value value; memset(value.arr, 0, sizeof(value.arr)); value.var= 456; struct iovec iov[4]; iov[0].iov_base = &key.id; iov[0].iov_len = sizeof(key.id); iov[1].iov_base = &value.arr; iov[1].iov_len = sizeof(value.arr); iov[2].iov_base = &value.var; iov[2].iov_len = sizeof(value.var); iov[3].iov_base = &value.var2; iov[3].iov_len = sizeof(value.var2); struct msghdr msg; ... if (sendmsg(sockfd, &msg, 0) < 0) { ...
Advantage - no struct packing needed.
Disadvantage - the API is greatly weakened.
Which way is the worst? Is there any other options?