Использование потока для обработки полученных данных - PullRequest
0 голосов
/ 25 февраля 2020

Я получаю сообщения из сокета. Сокет упакован в заголовок (это в основном размер сообщения) и нижний колонтитул, который является cr c (своего рода код, чтобы проверить, не повреждено ли сообщение)

Итак, макет выглядит примерно так:

size (2 bytes) | message (240 bytes) | crc (4 byte)

Я написал operator>>

operator>> выглядит следующим образом:

std::istream &operator>>(std::istream &stream, Message &msg) {
    std::int16_t size;
    stream >> size;
    stream.read(reinterpret_cast<char*>(&msg), size);

    // Not receive enough data
    if (stream.rdbuf()->in_avail() < dataSize + 4) {
        stream.setstate(std::ios_base::failbit);
        return stream;
    }

    std::int16_t gotCrc;
    stream >> gotCrc;

    // Data not received correctly
    if(gotCrc != computeCrc(msg)) {
        stream.setstate(std::ios_base::failbit);
    }
    return stream;
}

Сообщение может поступать побайтово или может прибыть полностью. Мы можем даже получить несколько сообщений за один раз.

По сути, я сделал что-то вроде этого:

struct MessageReceiver {
    std::string totalDataReceived;
    void messageArrived(std::string data) {
        // We add the data to totaldataReceived
        totalDataReceived += data;

        std::stringbuf buf(totalDataReceived);
        std::istream stream(&buf);
        std::vector<Message> messages(
            std::istream_iterator<Message>(stream), 
            std::istream_iterator<Message>{});
        std::for_each(begin(messages), end(messages), processMessage);
        // +4 for crc and + 2 for the size to remove
        auto sizeToRemove = [](auto init, auto message) {return init + message.size + 4 + 2;};
        // remove the proceed messages
        totalDataReceived.remove(accumulate(begin(messages), end(messages), 0, sizeToRemove);
    }
};

Итак, в основном, мы получаем данные, мы вставляем их в общий массив данных получил. Мы транслируем его, и если мы получили хотя бы одно сообщение, мы удаляем его из буфера totalDataReceived.

Однако я не уверен, что это хороший способ для go. На самом деле, этот код не работает, когда вычисление неверно cr c ... (сообщение не создано, поэтому мы не повторяем его). Поэтому каждый раз я буду пытаться прочитать сообщение с ошибкой cr c ...

Как я могу это сделать? Я не могу сохранить все данные в totalDataReceived, потому что я могу получать много сообщений в течение времени выполнения.

Должен ли я реализовать свой собственный streambuf?

1 Ответ

1 голос
/ 25 февраля 2020

Я обнаружил, что вы хотите создать класс, который действует как std :: istream. Конечно, вы можете создать свой собственный класс, но я предпочитаю реализовывать std :: streambuf по некоторым причинам.

Во-первых, люди, использующие ваш класс, привыкли использовать его, так как он действует так же, как std :: istream, если вы наследуете и реализуете std :: streambuf и std :: istream.

Во-вторых, вам не нужно создавать дополнительный метод или не нужно переопределять операторы. Они уже готовы на уровне класса std :: istream.

Чтобы реализовать std :: streambuf, вам нужно унаследовать его, переопределить underflow () и установить указатели get с помощью setg ().

...