Tcp 你如何解释这个短语?

Tcp 你如何解释这个短语?,tcp,binary,protocols,checksum,Tcp,Binary,Protocols,Checksum,你如何解释这个短语 校验和 这是在从报头到校验和的低8位相加时使零的值 根据本协议说明: 协议 由标头(1字节)+数据长度(1字节)组成+ 命令数据(13字节)+校验和(1字节)+连接ID(1字节 字节) (我从字面上复制了这个协议描述,所以我不知道为什么会有1个字节(复数)。但我可以告诉你它只有一个字节) 以下是此协议的一些TCP数据包示例: HE:DL:------------Command Data -------------:CS:ID 02:0d:be:ef:03:06:00:19:d

你如何解释这个短语

校验和
这是在从报头到校验和的低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
    是标题(固定为
    0x02
  • DL
    是数据长度(始终为
    0x0d
    ,因为数据包的长度都相同)
  • CS
    是校验和(这是我的问题)
  • ID
    是连接ID(在我的测试中似乎总是01)
我搞不懂校验和是如何计算的。我希望我提供了足够的信息


提前谢谢。

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

0x0313 0000 0011 0001 0011
0x00ED 0000 0000 1110 1101
当它像那样排列时,您可以清楚地看到您将清零较低的8位并返回:

0x0400 0000 0100 0000 0000

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

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

0x0313 0000 0011 0001 0011
0x00ED 0000 0000 1110 1101
当它像那样排列时,您可以清楚地看到您将清零较低的8位并返回:

0x0400 0000 0100 0000 0000

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

如果您将标头、DataLength、CommandData和校验和中的所有十六进制数相加,则为1024

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

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

编辑:
它不必求和到1024,相反,如果它是有效的,它将求和到8个低位为0的数字,例如1024(1000000000)、768(1100000000)和1280(10100000000)。

如果您将头中的所有十六进制数、数据长度、CommandData和校验和相加,则为1024

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

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

编辑: 它不一定要求和到1024,相反,如果它是有效的,它将求和到8个低位为0的数字,例如1024(1000000000)、768(1100000000)和1280(10100000000)。

  • 将校验和字段前的所有字节相加
  • 提取和的低8位
  • 求一个值(“值为零”),该值在与计算和相加时变为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);
    }
    
    uint8\u-t-chksum(const-uint8\u-t*数据,大小长度)
    {
    尺寸i;
    无符号整数chk=-1;
    对于(i=0;i

  • 将校验和字段前的所有字节相加
  • 提取和的低8位
  • 求一个值(“值为零”),该值在与计算和相加时变为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);
    }
    
    uint8\u-t-chksum(const-uint8\u-t*数据,大小长度)
    {
    尺寸i;
    无符号整数chk=-1;
    对于(i=0;i
    为了好玩,我将此作为使用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;
    }
    

    为了好玩,我将此作为使用BoostSpirit(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;
    }
    

    啊哈!我找到了。它包括标题。啊哈!我找到了。它包含标题。这是解决方案,但它不是完全有效的。我得到的是768、1024和1280的总和。你能把总和不正确的数据包发出去吗?也许他们在运输途中被损坏了。您提供的所有示例似乎都有效。(参见我帖子中添加的屏幕截图)768、1024和1280都是有效的。当校验和正常时,字节和校验和字节之和的低8位将为0。我知道。这就是我写“这就是解决方案”的原因。请注意,您的评论的最后一句不是真的。校验和字节将不是0。(字节总和&0xFF)将为零。这就是为什么校验和字节用于:使和为零。这是解决方案,但并不完全有效。我得到的是768、1024和1280的总和。你能把总和不正确的数据包发出去吗?也许他们在运输途中被损坏了。您提供的所有示例似乎都有效。(参见我帖子中添加的屏幕截图)768、1024和1280都是有效的。当校验和正常时,字节和的低8位