你如何解读这句话?

发布于 2024-12-05 12:13:23 字数 1053 浏览 1 评论 0原文

你如何解读这句话?

校验和
这是在将标头中的低 8 位添加到校验和时要使零的值。

有了这个协议描述:

协议
由头(1字节)+数据长度(1字节)+组成 命令数据(13字节)+校验和(1字节)+连接ID(1 字节)。

(我逐字复制了这个协议描述,所以我不知道为什么有 1 个字节(复数)。但我可以告诉你它只是一个字节)

这里是该协议的一些示例 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 是 HEader(固定为 0x02
  • DL 是 DataLength(始终为 < code>0x0d,因为数据包都是相同的长度)
  • CS是CheckSum(这是我的问题)
  • ID是连接ID(在我的测试中似乎总是01)

我无法弄清楚如何计算校验和。我希望我提供了足够的信息。

提前致谢。

How do you interpret this phrase?

Checksum
This is the value to make zero on the addition of the lower 8 bits from the header to the checksum.

With this protocol description:

Protocol
Consist of header (1 byte) + data length (1 byte) +
command data (13 bytes) + check sum (1 bytes) + connection ID (1
byte).

(I literally copied this protocol description, so I'dont know why there is 1 bytes (in plural). But I can tell you it is only one byte)

Here are some sample TCP packets of this protocol:

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

Where

  • HE is the HEader (which is fixed to 0x02)
  • DL is the DataLength (which is always 0x0d, because the packets are all the same length)
  • CS is the CheckSum (which is my question about)
  • ID is the connection ID (seems to be always 01 in my tests)

I can't figure out how the checksum is computed. I hope I gave enough info.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

笑着哭最痛 2024-12-12 12:13:23

我认为只是描述中有错误。看起来他们正在对标头和校验和之间的所有字节求和。校验和只是清除低 8 位的数字。因此,对于第一个示例,标头和校验和之间的所有字节之和为 0x0313。或者

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

当它像这样排列时,您可以清楚地看到您将把低 8 位清零并返回:

0x0400 0000 0100 0000 0000

您没有指定语言,但您也可以通过执行 (0 XOR returned) + 来快速计算自己的校验和1.

I think there's just an error in the description. It looks like they are summing all the bytes between the header and the checksum. And the checksum is just a number that clears the lower 8 bits. So, for the first example, the sum of all bytes between the header and the checksum is 0x0313. Or

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

When it's lined up like that, you can clearly see you'll be zeroing out the lower 8 bits and returning:

0x0400 0000 0100 0000 0000

You didn't specify a language, but you could also quickly calculate your own checksum by doing (0 XOR calculatedSum) + 1.

献世佛 2024-12-12 12:13:23

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

You

  1. Sum up all the bytes before the check sum field.
  2. Extract the low 8 bits of the sum
  3. Find the value("value to make zero"), that, when added to the computed sum becomes 0 (i.e. you solve "x + computed sum = 0")

Anyway, this C code computes the correct sum for all your 4 examples:

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);
}
街道布景 2024-12-12 12:13:23

如果将 Header、DataLength、CommandData 和 CheckSum 中的所有十六进制数字相加,则为 1024。

例如,这是第二个示例的总和(我跳过了 0x00):

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

屏幕截图(sum 只是我编写的一个 javascript 函数自动对十六进制值求和):

Screenshot shown sum

编辑:
它不一定会等于 1024,相反,如果有效,它会等于一个低 8 位为 0 的数字,例如 1024 (10000000000)、768 (1100000000 )和 1280 (10100000000)。

If you add up all the hex numbers in the Header, DataLength, CommandData, and CheckSum, it makes 1024.

For example, here's the sum of the second example (I skipped the 0x00's):

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

Screenshot (sum is just a javascript function I wrote to sum the hex values automatically):

Screenshot showing sum

EDIT:
It will not necessarily sum to 1024, rather, if it is valid it will sum to a number where the 8 lower bits are 0, such as 1024 (10000000000), 768 (1100000000), and 1280 (10100000000).

铜锣湾横着走 2024-12-12 12:13:23

只是为了好玩,我将此作为使用 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

Just for fun, I took this as an exercise in writing a simple binary parser using Boost Spirit (c++). I included the conversion from the question format and the checksum verification.

I made the parser recognize actual datalength and arbitrary choice of STL container for the packet data. Output below:

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

Output

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文