1

I am trying to send raw bits from a boost::dynamic_bitset with the Winsock2 sendto function. MS documentation shows that sendto uses const char * type for the buffer parameter. How do I send only the raw bits stored in the dynamic_bitset? I don't know how to cast or manipulate the dynamic_bitset so that it can be used in the sendto function.

Here are some relevant lines from my program:

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <system_error>
#include <boost/dynamic_bitset/dynamic_bitset.hpp>
#pragma comment(lib, "ws2_32.lib")
using boost::dynamic_bitset;
dynamic_bitset<> getDynamicBitset() {
 //code to return a dynamic_bitset here
}
//create a dynamic bitset from a function
dynamic_bitset<> db1 = getDynamicBitset(); 
//manipulation of dynamic_bitset needed here to make it work in sendto as the buffer parameter
int ret = sendto(sock, buffer, len, flags, reinterpret_cast<SOCKADDR*>(&address), sizeof(address));

I am using the sample code from Peter R here: How do I receive udp packets with winsock in c++?

Also, my question is related to this, but I'm using C++ and not C. Sending a structure in the sendto() function - C language

I'm new to C++ and barely understand pointers and type manipulation.

Thanks.

asked Jan 26, 2021 at 17:24
8
  • What structure will eventually the bits end up in on the other side? Will it also be a boost dynamic_bitset? Commented Jan 26, 2021 at 17:33
  • I'm not sure, and maybe that's the problem. Ultimately I want programs on the network that are listening for Protocol Data Units to receive and interpret them. en.wikipedia.org/wiki/Protocol_data_unit - see SISO-REF-010-2020 and IEEE 1278.1-2012 Commented Jan 26, 2021 at 17:39
  • You could send the data as a string of 0 and 1 characters if that meets the requirements. Commented Jan 26, 2021 at 17:40
  • 1
    @PaulMcKenzie But why would you do that? That would take eight times the bandwidth Commented Jan 26, 2021 at 17:54
  • Since a dynamic bitset can be an unlimited number of bits, the other option would be to send the bits in maybe 32-bit or 64-bit chunks. @OP -- This isn't really that much of a C++ issue -- the dynamic bitset has all of the functions needed to see if a particular bit is set. It's just a matter of putting together an array that can be sent over the socket. All C++ does is to make the access of each bit a convenient class member function. A C program would look no different, except the function would probably be called "GetBit" or "IsBitSet". Commented Jan 26, 2021 at 18:08

1 Answer 1

1

I've implemented serialization for dynamic_bitset before: How to serialize boost::dynamic_bitset?

You can use that or a similar technique based on the same interfaces:

template <typename Block, typename Alloc>
std::string to_binary_string(boost::dynamic_bitset<Block, Alloc> const& bs) {
 uint32_t const num_bits = bs.size();
 auto const num_blocks = div_roundup(num_bits, sizeof(Block)*CHAR_BIT);
 // prepare zeroed output buffer
 std::string buf(sizeof(num_bits) + num_blocks * sizeof(Block), '0円');
 // write size prefix 
 std::memcpy(buf.data(), &num_bits, sizeof(num_bits));
 // write block data
 if (num_bits > 0) { // mustn't pass nullptr to src argument of memcpy
 auto b = reinterpret_cast<Block*>(buf.data() + sizeof(num_bits));
 to_block_range(bs, b);
 }
 return buf;
}

Which you could send like:

std::string buf = to_binary_string(my_bitset);
int ret = sendto(sock, buf.data(), buf.size(), flags, reinterpret_cast<SOCKADDR*>(&address), sizeof(address));

The analogous deserialization code:

template <typename Block, typename Alloc>
void from_bytes(std::string_view buf, boost::dynamic_bitset<Block, Alloc>& bs) {
 // read the size prefix
 uint32_t num_bits;
 if (buf.size() < sizeof(num_bits)) {
 throw std::length_error("from_bytes");
 }
 std::memcpy(&num_bits, buf.data(), sizeof(num_bits));
 // shift buf to only cover the actual bit data
 buf = buf.substr(sizeof(num_bits));
 // read the bits as blocks
 bs.resize(num_bits);
 if (buf.size() % sizeof(Block) != 0) {
 throw std::length_error("from_bytes");
 }
 auto b = reinterpret_cast<Block const*>(buf.data());
 auto e = reinterpret_cast<Block const*>(buf.data() + buf.size());
 size_t const num_blocks = std::distance(b, e);
 
 // sanity checks block count vs num_bits
 if (num_blocks != div_roundup(num_bits, sizeof(Block)*CHAR_BIT)) {
 throw std::length_error("from_bytes"); // num_blocks doesn't match num_bits
 }
 from_block_range(b, e, bs);
 bs.resize(num_bits);
}

Live Demo

Disclaimer:

  • Portability is NOT addressed here. If you send data across systems using different native byte orderings, the behaviour is unspecified, even though care has been taken to not BLOW UP, the data would be wrong even in the extremely unlikely event that the sizes would add up.
  • Similarly, no guarantees are made when the deserialized type doesn't exactly match the serialized type in terms of Block type.

That aside, the program tests edge cases and runs clean under ASAN/UBSAN.

Live On Coliru

#include <boost/dynamic_bitset.hpp>
#include <climits> // CHAR_BIT
#include <string>
#include <string_view>
// demo output
#include <iostream>
static inline size_t div_roundup(size_t p, size_t q) {
 // quick&dirty, see https://stackoverflow.com/a/926806/85371
 return (p+q-1)/q;
}
template <typename Block, typename Alloc>
std::string to_binary_string(boost::dynamic_bitset<Block, Alloc> const& bs) {
 uint32_t const num_bits = bs.size();
 auto const num_blocks = div_roundup(num_bits, sizeof(Block)*CHAR_BIT);
 // prepare zeroed output buffer
 std::string buf(sizeof(num_bits) + num_blocks * sizeof(Block), '0円');
 // write size prefix 
 std::memcpy(buf.data(), &num_bits, sizeof(num_bits));
 // write block data
 if (num_bits > 0) { // mustn't pass nullptr to src argument of memcpy
 auto b = reinterpret_cast<Block*>(buf.data() + sizeof(num_bits));
 to_block_range(bs, b);
 }
 return buf;
}
template <typename Block, typename Alloc>
void from_bytes(std::string_view buf, boost::dynamic_bitset<Block, Alloc>& bs) {
 // read the size prefix
 uint32_t num_bits;
 if (buf.size() < sizeof(num_bits)) {
 throw std::length_error("from_bytes");
 }
 std::memcpy(&num_bits, buf.data(), sizeof(num_bits));
 // shift buf to only cover the actual bit data
 buf = buf.substr(sizeof(num_bits));
 // read the bits as blocks
 bs.resize(num_bits);
 if (buf.size() % sizeof(Block) != 0) {
 throw std::length_error("from_bytes");
 }
 auto b = reinterpret_cast<Block const*>(buf.data());
 auto e = reinterpret_cast<Block const*>(buf.data() + buf.size());
 size_t const num_blocks = std::distance(b, e);
 
 // sanity checks block count vs num_bits
 if (num_blocks != div_roundup(num_bits, sizeof(Block)*CHAR_BIT)) {
 throw std::length_error("from_bytes"); // num_blocks doesn't match num_bits
 }
 from_block_range(b, e, bs);
 bs.resize(num_bits);
}
int main() {
 ::srand(::time(0)); // extremely lazy bad random, sue me
 for (auto bits = 0; bits < 128; ++bits) {
 boost::dynamic_bitset<> my_bitset(bits), roundtrip;
 for (size_t bit = 0; bit < my_bitset.size(); ++bit)
 my_bitset.set(bit, rand()%2);
 from_bytes(to_binary_string(my_bitset), roundtrip);
 std::cout << "{" << roundtrip << "} " << (roundtrip == my_bitset? "OK":"ERROR") << std::endl;
 }
}

Printing:

{} OK
{0} OK
{11} OK
{001} OK
{0010} OK
{01000} OK
{110011} OK
{0101011} OK
{01101101} OK
{101011011} OK
{1011100010} OK
{11100100110} OK
{110010010000} OK
{0011100110110} OK
{11100110110001} OK
{111101110011011} OK
{1011101100011011} OK
{10101000000110111} OK
{000000110100111111} OK
{0110001110100001011} OK
{11111111010010010110} OK
{010011100110111000011} OK
{0110011101111000111000} OK
{10011100110001001110101} OK
{011001001100011111010011} OK
{1101010010110100000100101} OK
{01101111001100100010111110} OK
{010101111001011111100011000} OK
{0101111001111001000001011011} OK
{10011101100111110110110001010} OK
{000001110000100011000011101000} OK
{1101010001101101111001001110000} OK
{11111010100111110010101111110010} OK
{110010101001101110000001011101110} OK
{1010100100010000011011011010000111} OK
{11101101111011011010110101101010000} OK
{110000101010100111010111011110100010} OK
{1000111110000001111010110000001111010} OK
{00010010011001111101101110101111000000} OK
{000000011000001100101000111110000111101} OK
{1000111111000000000111101110111101100010} OK
{01001110000011011100111110100100010111011} OK
{001000011101111001110111110000110100011001} OK
{0011010001000110100101000010110000101101001} OK
{01110111010111101000011110110011011110110101} OK
{111001000011011110001100000111001000001101010} OK
{1110001101010100101110100111001010100111111001} OK
{00110110011111110001110111110101101010100000110} OK
{101000100110100111001000110111010101101011000011} OK
{0011111001111000011010110110111110111011001101000} OK
{00011100110101100011000001010000111001011001111111} OK
{100101100001101111011001000101110100111110000100001} OK
{1110101000000100001111100111101101111100100011111111} OK
{00001010100111101001000100010111101101100101000001110} OK
{110101000110000011000100000001100100111101001100110011} OK
{1001111110001011100010011110001011010111101010101100100} OK
{00101001010011101000100110011011110101100110000110100010} OK
{010101000111011001001010011001010110111110101011001100100} OK
{0101100010000001010001110011001100000001011101101010110000} OK
{01000111001101100011000010010010111010010010111101101001010} OK
{000111101101111000011101101101101101100001011110111000001000} OK
{0111101011101011101000011001010000011001010111001001111000011} OK
{01000100010000000110001110110010110100001000001011110000010011} OK
{110100101010111101010010011100110000110100001010110100110001011} OK
{0111110001111011011001110000101100111011010000000101111010000111} OK
{01101000000101000000010010010100010101000110100011001010011011011} OK
{110111111011010011011001001011000100010000100001001000000111110011} OK
{0000111000100111101000000001111000011100000101010100001101111101111} OK
{11100101011110110110101100100100110110110110000000000101000000000011} OK
{111011000011111101100101001010010010101110001001100110111100101011101} OK
{1001110011100111010010110011010111111001100110010011010100101000010010} OK
{01011111001100011100000000011100000111010111001111100001100110001111110} OK
{010010111000101000111100000000010011111110010110011110000000000000001100} OK
{1101010011010110010100000100100110100100100110011100011010000001000001011} OK
{10100101001110110001011010010101100100110100011011001000010110100001101010} OK
{101010100011101100111000111001011011010111000101101011111011000001010111110} OK
{1011011101011011000101101101000110011001001001110101010010001010111000101011} OK
{01100101111100011110101000001010111101011011100101111000101110011011110011100} OK
{111100111010011100010111101010110101110000100111011001001111001100001011111110} OK
{0000010110001101001001110010011011010111100010100001111010100000100000101010010} OK
{10010100010000110101000000101001011011001001000110110110110001000001001000011011} OK
{011011101100001101001110111110000111010111010011001100100010011111110000101101000} OK
{0011001100110110111111101010011111010001000001110001010000101110111100100010111101} OK
{10001101001110001000001110110011111010010111100101011100111110010100010111100001010} OK
{111100011111110011011001001111101111110001010100010000001101000000101001111110011000} OK
{1001100110101000000110001000101010100101110100011100100010111111010101101001110000011} OK
{11000111100001000001001010010011010101100100101100001100101110010100000000000111100000} OK
{011011101010011001000000101101100011010110001000111010100001111000111001101011110111110} OK
{1011100111101110001111011101111010011100111111111110011010010000111101100000110111110000} OK
{11010010100011011010011111101011100101010100110100101001010011100011100001001000010001100} OK
{101100101110110110010010010001000010101100101010000110000100101111110100010111010111010000} OK
{1001100111111100000101011010100111101010000110010100100111011001010101111010100000000110011} OK
{11001000001101011000100011101111000001110011000100010011011011110010110001111001000101000010} OK
{010101110110011011001001111010100001101010110101001101010100110111011101001110111011111111001} OK
{0000001100010100101010000011000000100110011001011111101110100111011110100011011101001011001111} OK
{11101001010111000101001110011001010000000110010110011010100001000010011010010010010110110110100} OK
{100001001010100100000100111100101100000111111010110010101101000110010110010110011111110010111010} OK
{0110011101101011110011100101100110111110011110110001100101011000101110110001011110100000001010101} OK
{11111011101101010010010000101110000111011011001010001000000111101110110001000101110100110101001100} OK
{101001001001010101110010000100001000001101111111010000000110100111110001111010100100001001100100100} OK
{1010011111100001100101101110111001110011110100000100100100110011101110001000010000100001011101001101} OK
{10101011111010101101011101110010101111010001100011111000110011111011101110101110011011010111110011010} OK
{101001011011011011111101011110110000010001000011001011111100011000001100111100001000101111101000110100} OK
{1100001111000101010001010010000110011001111111011101100011111010100011110011011001001110010100111101010} OK
{01110111101110010010110110011011100101001010011010110010000011100111111101010110110001000111101011001011} OK
{111110001010000011111101001011100010111001001110001101001011100010111001011001111110001110111000010001010} OK
{1000110001111101001001100010011101011011000000001010111001111001100001001000101111001011010000011100100110} OK
{01101100101011110001001001101001110100111100111101000100010111101011000101101110101011010100011111110101111} OK
{100011010110010100001100010011111100101010011010110101001010000100011100011110000110111101000011011110010111} OK
{0001110100111110010010100101000111111101101110010011100110111101111001111111100101100000101110011011000001101} OK
{10000101011100100101100111111000010100011100010101111000001101010011111010011011011000110011000100110100101000} OK
{100110110011000000010000100011100010010101110000111010010101011000110101111101110011011101001011001101010001010} OK
{1001010100011011000111111111111001011010000001110100011100001101000001000010101000111110110010100101101111111111} OK
{00111000110111101110100111000110101111111101101100011111111110101010101001000000110000111101101111010011100011011} OK
{111100000100010001011010111001111111010111001101000100010011010110100111011010111101001110010001001111100110110010} OK
{1111110110110111110000001110010010100011000101001001111010001001111101111100000011000101001001001101000110000001100} OK
{11110101001111001100101001010100101110100011000101110001101101101110111101010101111011010100000110100011111011010101} OK
{100111000001000011100001011000001100100010101011110110001100010100001011111011000011100110011001101110011111101000101} OK
{1110110110010100001000101001001110100000110010110011110001111111110011111010000010111101001000110010011111001111101000} OK
{00000101100100000111110000100101010100101000011000111010110110111100111101111110110101100011101101011000000001001110111} OK
{010111011011000010001010010100010110001001101101101101001011010001000010010000000111011100100110101011001000001011011000} OK
{0011011110010110010111101101111100111110000010111101010001101111101101101001001000101101101001110000110000000110100010010} OK
{00001001010011101011011010010000000011000110011100000101111000100101111110101111100100011110100101011101101111100011100101} OK
{001011011110110000011010101000001001100100011001000100110100100111100101100010111101001010101100100100011010111010000101100} OK
{1111110110100111101011110100111011000001001111111010100011110001100100010010110110111110111100001011101000000100100000100100} OK
{01110000101110010101010110100001010010101010001111110100010111000011101000111010101111001011100111000011111011110011101011100} OK
{001100001010111010111001111011011000100100110010110001010000001110000001000110010101101000111110010101001010101100010111100011} OK
{1100011010110110001110101000110011110110010011010101110001010111110010000110011111110101111010110001010100110010000101001110011} OK
answered Jan 26, 2021 at 18:50
Sign up to request clarification or add additional context in comments.

1 Comment

Found some more time to do the whole exercise properly (Live Demo). Now it serializes the size as well as the bit data in binary form. See answer text for disclaimer.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.