Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

C++ send boost::dynamic_bitset with Winsock2 sendto function

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.

question from:https://stackoverflow.com/questions/65906150/c-send-boostdynamic-bitset-with-winsock2-sendto-function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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), '');

    // 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), '');

    // 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
{11000

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...