CH395 组播应用补充(2)
阅读本文前请先阅读下方链接文章了解组播应用流程,本文是对其的补充说明
CH395 组播应用补充(1) - Lqqq123 - 博客园
阅读完上述文章后,可以发现,当用CH395的IPRAW模式组IGMP包定期加入某一组时,这个所组的IGMP入组包中的检验和字段(2字节)是先随机填入一个值,再根据wireshark算出来的实际值填入,本文就是针对此处提供一个校验字段的算法,供使用参考。
如下,是一个完整的需要发出的入组包,其中0x95,0x29是两字节的校验和
1 UINT8 MyBuffer[16] = { 2 0x22,0x00, 3 0x95,0x29, 4 0x00,0x00,0x00,0x01, 5 0x04,0x00,0x00,0x00, 6 0xe0,0x64,0x64,0x70,//224.100.100.112 7 };//调用send函数用ipRaw模式的socket将这一包数据发出即可加入组播:CH395SendData(sock_id,MyBuffer,sizeof(MyBuffer));
那是如何算出来的?
1.首先将校验和字段置0,及把0x95,0x29写为0x00,0x00
2.将数据分为16位进行相加(若产生进位,则将进位加到最低位)
比如上面的数据包,先将数据按16位分组,即分为:0x2200,0x0000,0x0000,0x0001,0x0400,0x0000,0xe064,0x6470
然后按位相加:
0x2200+0x0000+0x0000+0x0001+0x0400+0x0000+0xe064 = 0x10665,注意到此时已经超过了16位产生了进位,所以要先将进位加到最低位,如下
0x10665 = 0001 0000 0110 0110 0101(二进制),即0000 0110 0110 0101(低16位) + 0001(剩下的高位) = 0000 0110 0110 0110 = 0x0666;
再加上之前剩下的一个0x6470,
即0x0666+ 0x6470 = 0x6A6D = 0110 1010 1101 0110
全部算完后取反: = 1001 0101 0010 1001 = 0x9529
可以看到,最后算出来的检验和字段和之前对的上,就是0x95 0x29
最后将算出来的校验值填入数据中的对应位置即可。
附上实现代码供参考:
1 // 计算IGMP校验和的函数 2 uint16_t calculate_igmp_checksum(const uint8_t *packet, size_t length) { 3 uint32_t sum = 0; 4 const uint16_t *data = (const uint16_t *)packet; 5 size_t i; 6 // 确保长度是偶数,如果不是则补零 7 if (length % 2 == 1) { 8 length++; 9 } 10 // 对数据按16位进行累加 11 for (i = 0; i < length / 2; i++) { 12 sum += data[i]; 13 while (sum >> 16) { 14 sum = (sum & 0xFFFF) + (sum >> 16); // 处理进位 15 } 16 } 17 sum = ~sum; // 对累加和取反 18 return (uint16_t)sum; 19 } 20 int main() { 21 // 示例 22 uint8_t igmp_packet[] = { 23 0x22,0x00, 24 0x00,0x00, //校验位先置0 25 0x00,0x00,0x00,0x01, 26 0x04,0x00,0x00,0x00, 27 0xe0,0x64,0x64,0x70, //224.100.100.112 28 }; 29 size_t packet_length = sizeof(igmp_packet); 30 uint16_t checksum = calculate_igmp_checksum(igmp_packet, packet_length); 31 printf("IGMP Checksum: 0x%04X\n", checksum); 32 return 0; 33 }
浙公网安备 33010602011771号