Как вы интерпретируете эту фразу? - PullRequest
1 голос
/ 17 сентября 2011

Как вы интерпретируете эту фразу?

Контрольная сумма
Это значение, равное нулю при добавлении младших 8 битов из заголовка к контрольной сумме.

С этим описанием протокола:

Протокол
Состоит из заголовка (1 байт) + длина данных (1 байт) + командаданные (13 байт) + контрольная сумма (1 байт) + идентификатор соединения (1 байт).

(я буквально скопировал это описание протокола, поэтому я не буду знать, почему существует 1 bytes (во множественном числе). Но я могу сказать, что это только один байт)

Вот некоторые примеры TCP-пакетов этого протокола:

HE:DL:------------Command Data -------------:CS:ID
02:0d:be:ef:03:06:00:19:d3:02:00:00:60:00:00:ed:01
02:0d:be:ef:03:06:00:cd:d2:02:00:00:20:00:00:7a:01
02:0d:be:ef:03:06:00:10:f6:02:00:ba:30:00:00:49:01
02:0d:be:ef:03:06:00:c8:d8:02:00:20:30:00:00:49:01
// Requested Packets
02:0d:be:ef:03:06:00:13:d3:01:00:02:30:01:00:21:01
02:0d:be:ef:03:06:00:c2:ff:02:00:90:10:00:00:d8:01

Где

  • HE - заголовок (который установлен на 0x02)
  • DL - это DataLength (который всегда равен 0x0d, поскольку все пакеты имеют одинаковую длину)
  • CS - это CheckSum (о чем я и спрашиваю)
  • ID - это идентификатор соединения (в моих тестах он всегда равен 01)

Я могу't выяснить, как вычисляется контрольная сумма.Я надеюсь, что дал достаточно информации.

Заранее спасибо.

Ответы [ 4 ]

3 голосов
/ 18 сентября 2011

Я думаю, что в описании просто ошибка. Похоже, они суммируют все байты между заголовком и контрольной суммой. А контрольная сумма - это просто число, которое очищает младшие 8 бит. Итак, для первого примера сумма всех байтов между заголовком и контрольной суммой равна 0x0313. Или

0x0313 0000 0011 0001 0011
0x00ED 0000 0000 1110 1101

Когда это выстроено таким образом, вы можете ясно видеть, что вы обнуляете младшие 8 бит и возвращаете:

0x0400 0000 0100 0000 0000

Вы не указали язык, но вы также можете быстро рассчитать свою собственную контрольную сумму, выполнив (0 XOR рассчитанная сумма) + 1.

2 голосов
/ 18 сентября 2011

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

Я заставил парсер распознавать фактическую длину данных и произвольный выбор контейнера STL для пакетных данных.Вывод ниже:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace qi=boost::spirit::qi;
namespace karma=boost::spirit::karma;
namespace phx=boost::phoenix;

typedef unsigned char uchar;
static const auto inbyte  = qi::uint_parser<unsigned char, 16, 2, 2>();
static const auto outbyte = karma::right_align(2,'0') [ karma::hex ];

// for some reason the alignment doesn't 'take' with the above, so HACK:
#define outbyte karma::right_align(2,'0') [ karma::hex ]

struct packet_t
{
    enum { HEADER = 0x02 };
    uchar checksum, id;

    typedef std::string data_t;
    /// the following work without modification:
    // typedef std::vector<uchar> data_t; 
    // typedef std::list<int> data_t; 
    data_t data;

    uchar do_checksum() const 
    { 
        return (uchar) -std::accumulate(data.begin(), data.end(), 
            HEADER + data.size()); 
    }

    bool is_valid() const 
    { return checksum == do_checksum(); }
};

BOOST_FUSION_ADAPT_STRUCT(packet_t,
        (packet_t::data_t, data) (uchar, checksum) (uchar, id)); 

int main()
{
    static const std::string input = 
        "02:0d:be:ef:03:06:00:19:d3:02:00:00:60:00:00:ed:01\n"
        "02:0d:be:ef:03:06:00:cd:d2:02:00:00:20:00:00:7a:01\n"
        "02:0d:be:ef:03:06:00:10:f6:02:00:ba:30:00:00:49:01\n"
        "02:0d:be:ef:03:06:00:c8:d8:02:00:20:30:00:00:49:01\n"
        "02:08:c8:d8:02:00:20:30:00:00:49:01\n"; // failure test case

    // convert hex to bytes
    std::vector<std::vector<char> > rawpackets;
    if (!qi::parse(input.begin(), input.end(), (inbyte % ':') % qi::eol, rawpackets))
        { std::cerr << "bailing" << std::endl; return 255; }

    // std::cout << karma::format(karma::eps << outbyte % ':' % karma::eol, rawpackets) << std::endl;

    // analyze & checksum packets
    for (auto raw: rawpackets)
    {
        std::cout << karma::format(karma::eps << outbyte % ':', raw);

        using namespace qi;
        rule<decltype(raw.begin()), packet_t(), locals<uchar> > parser;
        parser %= byte_(packet_t::HEADER)
                > omit[ byte_ [ _a = _1 ] ] // datalen
                > repeat(_a)[byte_]         // data
                > byte_                     // checksum
                > byte_;                    // id

        packet_t packet;
        if (!parse(raw.begin(), raw.end(), parser, packet))
            { std::cerr << " bailing" << std::endl; return 255; }

        std::cout << " do_checksum():\t" << karma::format(outbyte, packet.do_checksum());
        std::cout << " is_valid():\t"    << std::boolalpha << packet.is_valid() << std::endl;
    }

    return 0;
}

Вывод

02:0d:be:ef:03:06:00:19:d3:02:00:00:60:00:00:ed:01 do_checksum():   ed is_valid():  true
02:0d:be:ef:03:06:00:cd:d2:02:00:00:20:00:00:7a:01 do_checksum():   7a is_valid():  true
02:0d:be:ef:03:06:00:10:f6:02:00:ba:30:00:00:49:01 do_checksum():   49 is_valid():  true
02:0d:be:ef:03:06:00:c8:d8:02:00:20:30:00:00:49:01 do_checksum():   49 is_valid():  true
02:08:c8:d8:02:00:20:30:00:00:49:01 do_checksum():  04 is_valid():  false
2 голосов
/ 18 сентября 2011

Вы

  1. Суммируйте все байты перед полем контрольной суммы.
  2. Извлечение младших 8 битов суммы
  3. Найти значение («значение, равное нулю»), которое при добавлении к вычисленной сумме становится равным 0 (т. Е. Вы решаете «x + вычисленная сумма = 0»)

В любом случае, этот код C вычисляет правильную сумму для всех ваших 4 примеров:

uint8_t silly_chksum(const uint8_t *data, size_t len)
{
  size_t i;
  unsigned int chk = -1;
  for(i = 0; i < len ;i++)
    {
        chk += data[i];
    }

    return ~(chk & 0xff);
}
1 голос
/ 18 сентября 2011

Если вы сложите все шестнадцатеричные числа в Header, DataLength, CommandData и CheckSum, это составит 1024.

Например, вот сумма второго примера (я пропустил 0x00):

0x02+0x0d+0xbe+0xef+0x03+0x06+0xcd+0xd2+0x02+0x20+0x7a = 1024

Снимок экрана (сумма - это просто функция javascript, которую я написал для автоматического суммирования шестнадцатеричных значений):

Screenshot showing sum

РЕДАКТИРОВАТЬ: Этосумма не обязательно будет равна 1024; скорее, если она действительна, она будет суммироваться с числом, где 8 младших битов равны 0, например 1024 (100 00000000 ), 768 (11 00000000 * 1016).*) и 1280 (101 00000000 ).

...