在上一篇文章中,我们通过直连电脑测试了CH395在组播环境中进行数据的收发,但在实际的使用场景中更多的是将CH395接入局域网环境中。因此,我们需要使用到一个协议——IGMP(Internet Group Management Protocol)。

  IGMP和ICMP一样,都是IP层的一部分。IGMP报文通过IP数据包进行传输,由20字节IP首部和8字节IGMP报文封装而成,其中IP首部的协议字段值为2来指明IGMP报文(重点,后续需要用上)。我们通过wireshark抓包可以发现电脑会不断的发送IGMP报文请求加入组播(图1示),而对比发现上一篇文章CH395的组播例程抓包中并没有发出该报文,所以CH395在路由环境中会不能正常收发组播数据。

图1 电脑端发送的IGMP报文

  那如何使用CH395发送该报文呢?这里教大家一个简单的快速使用方法。上面我们讲过IGMP报是通过IP数据报进行传输的,那我们就可以通过CH395的IP-RAW或者MAC-RAW的方式来自己封装该报文。那IGMP报文的内容该填写什么呢?电脑会发出组播请求报文,那我们就根据该报文来填充IP-RAW模式下的报文内容即可。

  用wireshark抓取一个电脑端发送的IGMP报文,分析后会发现如果使用IP-RAW模式,那前面的MAC地址和IP信息是不用我们填写了,该内容会在CH395的协议栈中自动填充(MAC-RAW就需要在程序里面填充全部内容了)。其中图2中示IGMP Verrsion:3表示IGMPv3协议;Type报文类型,取值为0x22(画重点,取值关系到发送出去的IGMP类型);Reserverd: 00 保留;Checksum:校验值(这个值可以根据算法算出来的,但本篇文章不涉及算法,所以后文会用最原始的方法填充);Num Group Records 1:已加入1个组;Group Record 224.0.0.251: 加入的组是224.0.0.251。

图2 IGMP报文内容

  分析完报文类型后,根据IP数据包的格式,我们应该需要填充内容为报文类型+保留值+校验值+加入组数量+保留值+要加入的组地址。接下来通过编写程序来实现CH395发送该报文。

  首先,根据官方手册图三示,配置socket为成IP-RAW模式,也就是协议类型为0。

图三 IP-RAW配置

  程序设定了socket3为IP-RAW模式来进行数据发送,目的地址是224.0.0.22(这是一个特殊地址空间,应用上有区别,下面会特别说明),配置程序如下:

const UINT8  Socket3DesIP[4] = {224,0,0,22};                       /* Socket 3目的IP地址(PC) */
void InitSocketParam(void){
   memset(&sockinf[0],0,sizeof(sockinf[0])); /* 将SockInf[0]全部清零*/
memcpy(&sockinf[0].IPAddr, BroadcastIP,sizeof(BroadcastIP)); /* 如果启用UDP SERVER功能,需将目的IP设为广播地址255.255.255.255 */
// sockinf[0].DesPort = Socket0DesPort; /* 目的端口 */
sockinf[0].SourPort= Socket0SourPort; /* 源端口 */
sockinf[0].ProtoType=PROTO_TYPE_UDP; /* UDP模式 */ memset(&sockinf[1],0,sizeof(sockinf[1])); /* 将SockInf[1]全部清零*/
memcpy(&sockinf[1].IPAddr, BroadcastIP,sizeof(BroadcastIP)); /* 如果启用UDP SERVER功能,需将目的IP设为广播地址255.255.255.255 */
// sockinf[1].DesPort = Socket1DesPort; /* 目的端口 */
sockinf[1].SourPort= Socket1SourPort; /* 源端口 */
sockinf[1].ProtoType=PROTO_TYPE_UDP; memset(&sockinf[2],0,sizeof(sockinf[2])); /* 将SockInf[2]全部清零*/
memcpy(&sockinf[2].IPAddr, BroadcastIP,sizeof(BroadcastIP)); /* 如果启用UDP SERVER功能,需将目的IP设为广播地址255.255.255.255 */
// sockinf[1].DesPort = Socket1DesPort; /* 目的端口 */
sockinf[2].SourPort= Socket2SourPort; /* 源端口 */
sockinf[2].ProtoType=PROTO_TYPE_UDP; memset(&sockinf[3],0,sizeof(sockinf[3])); /* 将SockInf[3]全部清零*/
memcpy(CH395Inf.IPAddr,Socket2DesIP,sizeof(Socket3DesIP)); /* 将目的IP地址写入 */
sockinf[3].ProtoType = PROTO_TYPE_IP_RAW; /* IP RAW模式 */
}
 

  设置socket3时,IPRawProto的协议段为02,上面说过IGMP在IP报中的协议类型为2。

const UINT8  IPRawProto = 0x02;    
void CH395SocketInitOpen(void)
{
UINT8 i; /* socket 0为UDP模式 */
CH395SetSocketDesIP(0,sockinf[0].IPAddr); /* 设置socket 0目标IP地址 */
CH395SetSocketProtType(0,sockinf[0].ProtoType); /* 设置socket 0协议类型 */
CH395SetSocketSourPort(0,sockinf[0].SourPort); /* 设置socket 0源端口 */
i = CH395OpenSocket(0); /* 打开socket 0 */
mStopIfError(i); CH395SetSocketDesIP(1,sockinf[1].IPAddr); /* 设置socket 1目标IP地址 */
CH395SetSocketProtType(1,sockinf[1].ProtoType); /* 设置socket 1协议类型 */
CH395SetSocketSourPort(1,sockinf[1].SourPort); /* 设置socket 1源端口 */
i = CH395OpenSocket(1); /* 打开socket 1 */
mStopIfError(i); CH395SetSocketDesIP(2,sockinf[2].IPAddr); /* 设置socket 2目标IP地址 */
CH395SetSocketProtType(2,sockinf[2].ProtoType); /* 设置socket 2协议类型 */
CH395SetSocketSourPort(2,sockinf[2].SourPort); /* 设置socket 2源端口 */
i = CH395OpenSocket(2); /* 打开socket 2 */
mStopIfError(i); /* socket 0为IP RAW模式 */
CH395SetSocketDesIP(3,CH395Inf.IPAddr); /* 设置socket 3目标地址 */
CH395SetSocketProtType(3,sockinf[3].ProtoType); /* 设置socket 3协议类型 */
CH395SetSocketIPRAWProto(3,IPRawProto); /* 设置协议字段,重点此时的IP报协议段为2 */
i = CH395OpenSocket(3); /* 打开socket 3 */
mStopIfError(i);
/* 检查是否成功 */
}

  完成socket3的IP-RAW模式初始化后就可以封装IGMP报文了,根据电脑抓包内容,我们在程序里定义一个Buffer来填充报文。IGMP中Mac地址和目的Ip都是已经在IP-RAW模式下CH395的内部协议栈自动封装,IP报类型也已填入。因此,Buffer中中需要填入0x22,0x00(IGMP类型、保留值);校验值随机填入两位0x01,0x02(后面会根据抓包修改);保留值填3个0x00;入组数量填1;最后填入Group Record信息:类型 :04;Len:00;Num:00;组播地址:e0:00:00:fb。

UINT8  MyBuffer1[24] = {
0x22,0x00,  
0x01,0x02,
0x00,0x00,0x00,0x01,
0x04,0x00,0x00,0x00,0xe0,0x00,0x00,0xfb,
};

  MAC-RAW方式需要自己手动全部添加报文内容(Buffer最后一行为0是为了满足以太网的最小帧64字节):

UINT8  MyBuffer1[] =
{
0x54,0xbf,0x64,0x1c,0x2a,0x9c,0xb4,0x05,0x00,0x00,
0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x2c,0x02,0x98,
0x00,0x00,0x01,0x02,0x13,0x16,0xc0,0xa8,0x01,0x0A,
0xe0,0x00,0x00,0x16,0x22,0x00,0xf9,0x02,0x00,0x00,
0x00,0x01,0x04,0x00,0x00,0x00,0xe0,0x00,0x00,0xfb,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

  在初始化的时候,一定设置一个CH395的TTL值(重点):

    InitSocketParam();                                               /* 初始化socket相关变量 */
CH395SocketInitOpen(); /*打开socket */
CH395SetTTLNum(3,1); /* 设置TTL值 */

  为什么要设置这个TTL值呢?因为我们的目的IP地址是224.0.0.22,而在TCP\IP协议规定中,这个地址其为特殊地址空间不能超过1跳(可以在TCPIP详解1卷中了解),图三示该IP时设置TTL为1的原因。

图三 特殊地址空间的TTL值

  设置完成后,可以在主函数循环调用CH395Senddata函数进行发送:CH395SendData(3,MyBuffer1,24)。提示:一般这个报文需要定时发送,因为有些路由或者交换机在一定时间内没有收到该设备的组播请求会踢出设备,所以应用时可以通过定时器来定时发送该报文。

  CH395初始化完成并启动后,通过Wireshark抓包会发现CH395发出了IGMP报文,但是打开报文分析会出现如图四示红色报错。

  图四 CH395发送的IGMP报文

  报错内容为校验值不对,0x01、0x02应该是0xF9、0x02,那我们就把Buffer中的01、02改成0xF9、0x02再看抓包结果如图五示。

图五 CH395的IGMP请求加入报文

  这时候wiresahrk的报文分析中没有出现红色报错了。但大家可能会发现电脑1.21发出的报文长度为54字节,而CH395的IP1.200发出的长度为60字节,是不是报文还是错的呢?不是,这是因为以太网帧最小为64字节,如果小于64字节就会有padding段填充,同时wireshark会不显示4字节的校验字段,减去该4字节就为60字长,图六示60字节的原因。

图六 CH395的60字长IGMP报文

  到这里CH395的IGMP就没问题了,CH395的IP-RAW和MAC-RAW方式例程已放到下面自取,关于IGMP报文里的校验值其实可以通过算法进行填充,但这里只是教大家一个快速简单的应用方法,如果感兴趣的可以根据网上的算法例程自行添加。

例程链接:https://files.cnblogs.com/files/blogs/805237/Socket-UdpMulticast.rar?t=1700655709&download=true

【WCH以太网接口系列芯片】基于CH395的组播请求(IGMP)的更多相关文章

  1. 海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器)

    海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器) 我在某个海思主控的项目中需要使用SPI接口来驱动一块液晶屏,液晶屏主控为 st7789,分辨率 240x240,图 ...

  2. nxp基于layerscape系列芯片的硬件型号解析

    每一种layerscape系列芯片都有两种硬件型号: RDB 和QDS RDB: Refrence Design Board QDS: QorIQ Development system

  3. 以太网接口TCP/IP协议介绍,说的很容易懂了

      以太网接口TCP/IP协议介绍,说的很容易懂了  TCP/IP协议,或称为TCP/IP协议栈,或互联网协议系列. TCP/IP协议栈(按TCP/IP参考模型划分) 应用层 FTP SMTP HTT ...

  4. [转帖]你不曾见过的国产CPU:可能是最全的龙芯系列芯片家谱(下)

    你不曾见过的国产CPU:可能是最全的龙芯系列芯片家谱(下) https://www.ijiwei.com/html/news/newsdetail?source=pc&news_id=7177 ...

  5. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  8. Nacos系列:基于Nacos的配置中心

    前言 在看正文之前,我想请你回顾一下自己待过的公司都是怎么管理配置的,我想应该会有以下几种方式: 1.硬编码 没有什么配置不配置的,直接写在代码里面,比如使用常量类 优势:对开发友好,开发清楚地知道代 ...

  9. STM32系列芯片命名规范

    1.STM32的基础知识 STM32是意法半导体公司,基于ARM Cortex®-M0,M0+,M3, M4和M7内核生产的系列通用MCU.截止当前时间为止(20190515),STM32有STM32 ...

  10. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

随机推荐

  1. Web通用漏洞--CSRF

    Web通用漏洞--CSRF 漏洞简介 CSRF(Cross Site Request Forgery, 跨站请求伪造/客户端请求伪造),即通过伪造访问数据包并制作成网页的形式,使受害者访问伪造网页,同 ...

  2. WPF的前世今生

    1.WPF的布局 WPF的布局分为相对定位和绝对定位两种. 绝对定位一般用Canvas 相对定位一般用Grid.StackPanel.DockPanel.WrapPanel 2.MVVM模式是什么 M ...

  3. 《Kali渗透基础》07. 弱点扫描(一)

    @ 目录 1:漏洞发现 1.1:Exploit-DB 1.2:searchsploit 1.3:nmap 2:漏洞管理 3:弱点扫描类型 4:漏洞基本概念 4.1:CVSS 4.2:CVE 4.3:O ...

  4. springboot整合feign的接口抽离

    前言 现在很多微服务框架使用feign来进行服务间的调用,需要在服务端和消费端两边分别对接口和请求返回实体进行编码,维护起来也比较麻烦.那有木有一种可能,只用服务端编写接口,客户端像本地方法一样调用, ...

  5. 防火墙&&firewalld&&iptables

    防火墙&&firewalld&&iptables 目录 防火墙&&firewalld&&iptables 一.firewalld 1.c ...

  6. PostgreSQL学习笔记-3.基础知识:CROSS、INNER、LEFT OUTER、RIGHT OUTER、FULL OUTER、UNION

    PostgreSQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段. 在 PostgreSQL 中,JOIN 有五种连接类型: CROSS JOIN :交叉连接INNER ...

  7. https://www.oracle.com/au/cloud/free/

    https://www.oracle.com/au/cloud/free/ "Oracle Cloud Free "免费云在线注册关于个人应用的用户在注册和试用的过程中遇到任何问题 ...

  8. 解决因对EFCore执行SQL方法不熟练而引起的问题

    前言 本文测试环境:VS2022+.Net7+MySQL 因为我想要实现使用EFCore去执行sql文件,所以就用到了方法ExecuteSqlAsync,然后就产生了下面的问题,首先因为方法接收的参数 ...

  9. P9140 [THUPC 2023 初赛] 背包

    prologue 这很难评(调了我 1h,我都想紫砂了. 还是典型得不重构就看不见系列. analysis 如果我们还是一个正常人,那么我们大体上是能看到题目的加粗字,这个格式很明显符合我们的同余最短 ...

  10. 报错Intel MKL FATAL ERROR: Cannot load libmkl_core.so.的一种解决方法

    问题 今天上80服务器跑mdistiller的代码时,意外发现torch.numpy都不能用了T_T 以torch为例,出现如下报错情况 以numpy为例,出现如下报错情况 我们先看看报错信息,这个报 ...