С++ отправить boost:: dynamic_bitset с функцией отправки Winsock2

Я пытаюсь отправить необработанные биты из boost:: dynamic_bitset с помощью функции отправки Winsock2. Документация MS показывает, что sendto использует тип const char * для параметра буфера. Как отправить только необработанные биты, хранящиеся в dynamic_bitset? Я не знаю, как преобразовать или манипулировать dynamic_bitset, чтобы его можно было использовать в функции sendto.

Вот несколько соответствующих строк из моей программы:

#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));

Я использую пример кода от Peter R здесь: Как я получаю пакеты udp с winsock в c++?

Кроме того, мой вопрос связан с этим, но я использую C++, а не C. c-language">Отправка структуры в функции sendto() - язык C

Я новичок в C++ и едва понимаю указатели и манипулирование типами.

Спасибо.


person Lee Exothermix    schedule 26.01.2021    source источник
comment
В какой структуре в конечном итоге биты окажутся на другой стороне? Будет ли это также усиление dynamic_bitset?   -  person PaulMcKenzie    schedule 26.01.2021
comment
Я не уверен, и, возможно, это проблема. В конечном счете, я хочу, чтобы программы в сети, прослушивающие блоки данных протокола, получали и интерпретировали их. en.wikipedia.org/wiki/Protocol_data_unit — см. SISO-REF-010-2020 и IEEE 1278.1-2012   -  person Lee Exothermix    schedule 26.01.2021
comment
Вы можете отправить данные в виде строки символов 0 и 1, если это соответствует требованиям.   -  person PaulMcKenzie    schedule 26.01.2021
comment
@PaulMcKenzie Но зачем тебе это? Это потребовало бы восьмикратного увеличения полосы пропускания.   -  person IWonderWhatThisAPIDoes    schedule 26.01.2021
comment
Поскольку динамический набор битов может состоять из неограниченного количества битов, другим вариантом может быть отправка битов 32-битными или 64-битными фрагментами. @OP - На самом деле это не такая большая проблема C ++ - динамический битовый набор имеет все функции, необходимые для проверки того, установлен ли конкретный бит. Это просто вопрос создания массива, который можно отправить через сокет. Все, что делает C++, — это делает доступ к каждому биту удобной функцией-членом класса. Программа на C не будет выглядеть иначе, за исключением того, что функция, вероятно, будет называться GetBit или IsBitSet.   -  person PaulMcKenzie    schedule 26.01.2021
comment
@IWonderWhatThisAPIDoes Наименьшая единица данных, которую сокет может отправлять/получать, — это байт, а не бит. Если в dynamic_bitset меньше 8 бит, вы все равно будете тратить пропускную способность на отправку неиспользуемых битов. Таким образом, вы также можете преобразовать данные dynamic_bitset в переносимый формат, например, в массив uintX[]. Вы сами сказали, что не знаете, использует ли другая сторона также dynamic_bitset, поэтому вы не можете просто отправить необработанные данные битового набора как есть, их необходимо сериализовать в форму, которую другая сторона может затем десериализовать во что угодно оно хочет.   -  person Remy Lebeau    schedule 26.01.2021
comment
Я думал о том, как лучше объяснить принимающую сторону — это будет протокол распределенного интерактивного моделирования (DIS). Для справки: размер пакета является переменным, но обычно это 1152 бита.   -  person Lee Exothermix    schedule 26.01.2021
comment
@IWonderWhatThisAPID на самом деле увеличивает пропускную способность в 256 раз.   -  person sehe    schedule 27.01.2021


Ответы (1)


Я реализовал сериализацию для dynamic_bitset раньше: Как сериализовать boost::dynamic_bitset?< /а>

Вы можете использовать этот или аналогичный метод, основанный на тех же интерфейсах:

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;
}

Который вы могли бы отправить как:

std::string buf = to_binary_string(my_bitset);

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

Аналогичный код десериализации:

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);
}

Живая демонстрация

Отказ от ответственности:

  • Переносимость здесь НЕ рассматривается. Если вы отправляете данные между системами, использующими другой собственный порядок байтов, поведение не указано, даже несмотря на то, что были приняты меры, чтобы не ВЗРЫВ, данные будут неправильными даже в крайне маловероятном случае, если размеры будут складываться.
  • Точно так же не дается никаких гарантий, если десериализованный тип не полностью соответствует сериализованному типу с точки зрения типа блока.

Кроме того, программа тестирует крайние случаи и работает без ошибок в ASAN/UBSAN.

Жить на 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;
    }
}

Печать:

{} 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
person sehe    schedule 26.01.2021
comment
Нашел еще немного времени, чтобы правильно выполнить все упражнение (Живое демо). Теперь он сериализует размер, а также битовые данные в двоичной форме. См. текст ответа для отказа от ответственности. - person sehe; 27.01.2021