Luke Vella
Luke Vella

Reputation: 746

How would I go about sending bit-fields through a socket?

I need to send a set of bit fields along with a string of characters from a client to a server.

So given I have:

#define YES 1
#define FLAG 2
int main(int argc, char* argv[])
{
    return sendToServer("The Message", YES | FLAG);
}
int sendToServer(char* msg, int bitfields)
{
   /* create socket and connect to server */
   /* Assume sock is set */
   send(sock, msg, strlen(msg), 0);
   return 0;
}

What would be the best way to send the bitfields? Is there anyway to send the bitfields along with the string?

EDIT: Ok I'm trying to implement Vlad's method. My client is pretty much identical to what he wrote. I have put the flag at the beginning data[0] and I used htonl instead of bswap. My server:

int main(int argc, char* argv[])
{
    /* create socket and wait for connection */
    char buffer[BUFFERSIZE];
    size_t rcvdB = recv(clntSock, buffer, sizeof(int),0);
    int flags = ntohl((int) buffer);
    rcvdB = recv(clntSock, buffer, sizeof(size_t),0);
    size_t msgSize = ntohl((size_t) buffer);
    rcvdB = recv(clntSock,buffer,msgSize,0);
    /* Then I send back to the client */
    ssize_t sntB = send(clntSock,buffer,msgSize,0);
}

When the client prints the message there are multiple ascii characters at the end of the message.

EDIT2:

The issue seems to occur when I read more than 8 bytes of data

Upvotes: 1

Views: 2736

Answers (4)

user405725
user405725

Reputation:

As others have pointed out, it depends on a protocol. I'd use something like this:

int sendToServer(char* msg, int bitfields)
{
   unsigned int bits = bswap32 (bitfields); // Convert host to network byte order.

   size_t len = strlen (msg);   // Calculate string length.
   size_t nlen = bswap64 (len); // Convert length's byte order from host to network.

   iovec data[3]; // Prepare 3 I/O buffers to send data by performing a single system call (they are expensive).

   // Send length of the string first.
   data[0].iov_base = &nlen;
   data[0].iov_len = sizeof (nlen);

   // Send string...
   data[1].iov_base = msg;
   data[1].iov_len = len;

   // And, of course, send bits.
   data[2].iov_base = &bits;
   data[2].iov_len = sizeof (bits);

   // Write all of those to the socket.
   writev (fd, &data, sizeof (data) / sizeof (data[0]));
}

On the receiving side, you can read the first sizeof (size_t) bytes, convert from network to host byte order, cast to size_t. That will tell you length of string. Then read buffer of that length - that will be your string. Finally, read another sizeof (int) bytes - that will be your bitfield.

See also:

Upvotes: 2

Fred Foo
Fred Foo

Reputation: 363507

This depends on your network protocol, of course. If you're designing it, and you have a maximum of 8 flags to send, put them in the first byte of the message. If you have at most 16, but them in the first two bytes, etc.

int sendToServer(int sock, char* msg, int flags)
{
    size_t siz = strlen(msg) + 1;  // +1 for NUL
    unsigned char *buf = malloc_or_die(siz + 1);
    buf[0] = flags;
    memcpy(buf + 1, msg, size);

    send(sock, msg, strlen(msg), 0);

    free(buf);
    return 0;
}

(I changed bitfields to flags since that's what they are. A bitfield is a collection of flags.)

Upvotes: 2

jwodder
jwodder

Reputation: 57460

It's probably best to send the bitfields as the bytes for a raw int (e.g., send(sock, &bitfields, sizeof(bitfields), 0)), making sure that the size & endianness is the same for both the client & server. It'd probably be easiest to send the bits before the string, as the server could then easily extract the string after a fixed number of bytes.

Upvotes: 1

Aif
Aif

Reputation: 11220

The bitfield forms a number, for instance 1|2 gives 3 since %01 | %10 = %11.

So all you have to send is that number. Kind of

snprintf(buffer, buffer_size, "%s-%d", message, number);
send(sockfd, buffer, buffer_size, 0);

Upvotes: 0

Related Questions