【WCH以太网接口系列芯片】基于CH395的组播请求(IGMP)
在上一篇文章中,我们通过直连电脑测试了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)的更多相关文章
- 海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器)
海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器) 我在某个海思主控的项目中需要使用SPI接口来驱动一块液晶屏,液晶屏主控为 st7789,分辨率 240x240,图 ...
- nxp基于layerscape系列芯片的硬件型号解析
每一种layerscape系列芯片都有两种硬件型号: RDB 和QDS RDB: Refrence Design Board QDS: QorIQ Development system
- 以太网接口TCP/IP协议介绍,说的很容易懂了
以太网接口TCP/IP协议介绍,说的很容易懂了 TCP/IP协议,或称为TCP/IP协议栈,或互联网协议系列. TCP/IP协议栈(按TCP/IP参考模型划分) 应用层 FTP SMTP HTT ...
- [转帖]你不曾见过的国产CPU:可能是最全的龙芯系列芯片家谱(下)
你不曾见过的国产CPU:可能是最全的龙芯系列芯片家谱(下) https://www.ijiwei.com/html/news/newsdetail?source=pc&news_id=7177 ...
- Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Nacos系列:基于Nacos的配置中心
前言 在看正文之前,我想请你回顾一下自己待过的公司都是怎么管理配置的,我想应该会有以下几种方式: 1.硬编码 没有什么配置不配置的,直接写在代码里面,比如使用常量类 优势:对开发友好,开发清楚地知道代 ...
- STM32系列芯片命名规范
1.STM32的基础知识 STM32是意法半导体公司,基于ARM Cortex®-M0,M0+,M3, M4和M7内核生产的系列通用MCU.截止当前时间为止(20190515),STM32有STM32 ...
- Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
随机推荐
- .NET爬取美图官网首页数据实战
前言: 在当今信息化社会,网络数据分析越来越受到重视.而作为开发人员,掌握一门能够抓取网页内容的语言显得尤为重要.在此篇文章中,将分享如何使用 .NET构建网络抓取工具.详细了解如何执行 HTTP 请 ...
- 部署属于自己的New bing Ai
该项目来源 https://github.com/adams549659584/go-proxy-bingai 项目体验地址 https://bing.vcanbb.top/web/#/ 项目介绍 基 ...
- Python 创建或读取 Excel 文件
Excel是一种常用的电子表格软件,广泛应用于金融.商业和教育等领域.它提供了强大的数据处理和分析功能,可进行各种计算和公式运算,并能创建各种类型的图表和可视化数据.Excel的灵活性使其成为处理和管 ...
- vue3封装筛选项
背景 项目开发中遇到筛选项,并且几个页面都有使用,依次写,太过于繁琐 筛选项解构如下 封装全局组件fjj-content <template> <div class="fj ...
- VulnStack - ATT&CK红队评估实战(一) Writeup
VulnStack - ATT&CK红队评估实战(一) Writeup VulnStack(一)环境搭建 项目地址 http://vulnstack.qiyuanxuetang.net/vul ...
- 从驾考科目二到自动驾驶,聊聊GPU为什么对自动驾驶很重要
"下一个项目,坡道起步." -- "考试不合格,请将车子开到起点,重新验证考试.你的扣分项是:起步时间超30秒:扣100分.行驶过程中车轮轧到边线:扣100分." ...
- HTML/网站一键打包APK工具(html网页打包安卓APP应用)
HTML一键打包APK工具使用说明 工具简介 HMTL一键打包APK工具可以把本地HTML项目或者网站打包为一个安卓应用APK文件,无需编写任何代码,也无需配置安卓开发环境,支持在最新的安卓设备上安装 ...
- 618京东到家APP-门详页反爬实战
一.背景与系统安全需求分析 1. 系统的重要性 上图所示是接口所属位置.对电商平台或在线商店而言,分类查商品都是很重要的,通过为用户提供清晰的商品分类,帮助他们快速找到所需产品,节省浏览时间,提升购物 ...
- 2023-09-16:用go语言,给你一个整数 n 和一个在范围 [0, n - 1] 以内的整数 p , 它们表示一个长度为 n 且下标从 0 开始的数组 arr , 数组中除了下标为 p 处是 1
2023-09-16:用go语言,给你一个整数 n 和一个在范围 [0, n - 1] 以内的整数 p , 它们表示一个长度为 n 且下标从 0 开始的数组 arr , 数组中除了下标为 p 处是 1 ...
- Dubbo3应用开发—XML形式的Dubbo应用开发和SpringBoot整合Dubbo开发
Dubbo3程序的初步开发 Dubbo3升级的核心内容 易⽤性 开箱即⽤,易⽤性⾼,如 Java 版本的⾯向接⼝代理特性能实现本地透明调⽤功能丰富,基于原⽣库或轻量扩展即可实现绝⼤多数的 微服务治理能 ...