全部例程

UDP组播

W5500 其他标签

2025/02/12 更新

本篇文章,我们将详细介绍如何在W5500芯片上面实现UDP组播(UDP Multicast)通信。并通过实战例程,为大家讲解如何使用UDP组播进行回环测试。

该例程用到的其他网络协议,例如DHCPUDP,请参考相关章节。有关初始化过程,请参考Network Install章节,这里将不再赘述。

UDP组播简介

UDP组播是一种数据传输方法,允许数据从一个源发送到多个目标设备,加入了相应组播组的接收者都可以接收到数据。这种方式非常高效,广泛应用于需要将相同数据同时传输给多个接收者的场景,如视频流媒体、实时数据分发和大规模软件更新等。IPv4的组播地址范围为 224.0.0.0 到 233.255.255.255。

UDP组播的特点

  • 基于UDP协议:UDP是无连接的协议,提供快速、低开销的数据传输,但不保证数据的可靠性、顺序性或重传。UDP组播继承了这些特性, 因此适合对实时性要求高、对可靠性要求较低的场景。
  • 高效数据传输: 发送者只需要发送一份数据,网络设备(如路由器、交换机)负责将数据复制并传输到所有组播成员。这种方式节省了带宽,相比单播更高效。
  • 不保证可靠性: 数据可能丢失,接收者需要自己处理数据包丢失问题。
  • 动态成员管理: 组播组的成员可以动态加入或离开,无需通知发送者。

UDP组播应用场景

接下来,我们了解下在W5500上,可以使用UDP组播完成哪些操作及应用呢?

  • 设备发现与自动配置: 实现设备自动发现和网络配置,如智能家居设备通过组播寻找网关或其他设备。
  • 实时数据广播: 用于传感器数据分发、工业控制和车联网中实时数据的高效传输。
  • 固件更新与配置分发: 对多个设备同时进行固件升级或统一下发配置,减少网络负担。
  • 告警和事件通知: 设备异常时实时向多个监控终端广播告警消息。
  • 时间同步: 用于局域网内的多设备时间同步,提升协同效率。
  • 测试与调试: 设备开发阶段,利用组播收集状态信息和日志数据

UDP组播环回测试工作流程

  1. 接收方通过IGMP协议加入组播组:IGMP(Internet Group Management Protocol)是一种网络层协议,用于管理主机和路由器间的组播组成员关系。 当接收方希望接收某个组播地址的数据时,会通过IGMP向路由器发送加入组播组的请求。
  2. 发送方发送测试数据:发送方通过UDP协议将数据包发送到指定的组播地址和端口。所有加入组播组的接收方均可接收到数据包。
  3. 接收方回传消息: 接收方在接收到组播数据后,主动回传响应消息到该组播组当中。回传的消息可以用于确认发送成功或测试链路的完整性。

UDP单播、组播和广播的区别

以下是UDP单播、组播和广播的区别:

报文解析

UDP协议报文已经在UDP章节中讲解过了,有关这部分的内容请参考相关章节,这里不再赘述。下面我们来讲解一下设备在加入组播时使用的IGMP报文。

IGMP 加入组播组时发送的报文是IGMP Membership Report报文。其格式如下:

字段解释

  1. 类型 (Type)

    值为 0x16(IGMPv2 Membership Report):表示主机请求加入组播组。

    值为 0x22(IGMPv3 Membership Report):用于支持 IGMPv3 的精细组播组管理。

  2. 校验和 (Checksum)

    计算方法基于标准的 IP 校验和算法。

    用于确保 IGMP 报文的完整性。

  3. 组地址 (Group Address)

    组播组的 IP 地址(范围:224.0.0.0 - 239.255.255.255)。

    加入时表示目标的组播地址。

报文示例


|报文原文|
16 00 08 f3 e0 01 01 0b

|报文解析|
Internet Group Management Protocol
    [IGMP Version: 2]
    Type: Membership Report (0x16)	(Type为0x16,表示主机请求加入组播组)
    Max Resp Time: 0.0 sec (0x00)	(最大响应时间为0)
    Checksum: 0x08f3 [correct]	(校验和为0x08f3)
    [Checksum Status: Good]
Multicast Address: 224.1.1.11	(组地址为224.1.1.11)
                  

实现过程

接下来,我们在W5500上实现UDP 组播回环测试。

UDP通信已经在硬件层面实现,因此我们只需要在主循环中调用udp_multicast()组播功能的函数即可,如下所示:


while (1)
{
  udp_multicast(SOCKET_ID, ethernet_buf, Multicast_mac, Multicast_IP, Multicast_port);
}

udp_multicast需要传入5个参数,分别是socket号,socket缓存,组播MAC地址,组播IP地址,组播端口号。 udp_multicast函数内容如下:


int32_t udp_multicast(uint8_t sn, uint8_t *buf, uint8_t *multicast_mac, uint8_t *multicast_ip, uint16_t 
multicast_port)
{
int32_t  ret;
uint16_t size, sentsize;
uint8_t  destip[4];
uint16_t destport, port = 50000;
switch (getSn_SR(sn))
{
case SOCK_UDP:
    if ((size = getSn_RX_RSR(sn)) > 0)
    {
        if (size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
        ret      = recvfrom(sn, buf, size, destip, (uint16_t *)&destport);
        buf[ret] = 0x00;
        printf("recv from [%d.%d.%d.%d][%d]: %s\r\n", destip[0], destip[1], destip[2], destip[3], 	 
destport, buf);
        if (ret <= 0)
        {
#ifdef _MULTICAST_DEBUG_
            printf("%d: recvfrom error. %ld\r\n", sn, ret);
#endif
            return ret;
        }
        size     = (uint16_t)ret;
        sentsize = 0;
        while (sentsize != size)
        {
            ret = sendto(sn, buf + sentsize, size - sentsize, destip, destport);
            if (ret < 0)
            {
#ifdef _MULTICAST_DEBUG_
                printf("%d: sendto error. %ld\r\n", sn, ret);
#endif
                return ret;
            }
            sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
        }
    }
    break;
case SOCK_CLOSED:
#ifdef _MULTICAST_DEBUG_
    printf("%d:Multicast Loopback start\r\n", sn);
#endif
    setSn_DIPR(sn, multicast_ip);
    setSn_DPORT(sn, multicast_port);
    setSn_DHAR(sn, multicast_mac);
    if ((ret = socket(sn, Sn_MR_UDP, port, Sn_MR_MULTI)) != sn)
        return ret;
#ifdef _MULTICAST_DEBUG_
    printf("%d:Opened, UDP组播 Socket\r\n", sn);
    printf("%d:Multicast Group IP - %d.%d.%d.%d\r\n", sn, multicast_ip[0], multicast_ip[1], 
multicast_ip[2], multicast_ip[3]);
    printf("%d:Multicast Group Port - %d\r\n", sn, multicast_port);
#endif
    break;
default:
    break;
}
return 1;
}

程序进入到udp_multicast函数后会执行一个状态机,根据Socket的状态来执行对应的操作。 当Socket处于SOCK_CLOSED状态时,函数会初始化Socket并加入组播组,然后打印Socket的状态和组播组的信息。

当Socket处于SOCK_UDP状态时,函数会检查是否有数据接收,如果有则将数据打印出来并发送回源地址。函数成功执行后返回1。

运行结果

请注意:

测试实例需要PC端和W5500处于同一网段,且连接的路由器需支持IGMP协议。

烧录例程运行后,首先进行了PHY链路检测,然后是DHCP获取网络地址结果,最后是进行UDP组播回环测试,如下图所示:

接下来,我们将打开一个支持加入 UDP 组播功能的网络调试工具。在使用该工具时,首先要完成必要的配置操作,具体包括设置监听组播和发送消息的相关参数。当完成上述配置后,我们向组播组发送消息,此时可以观察到串口会打印出我们所发送的消息,同时在网络调试工具的组播接收区域会收到相应的回环消息,组播回环测试流程得以正常运行。

请注意:

如果网络调试工具不支持加入组播,会导致收不到回环数据。这里我选的是gitcode上一个开源项目UDP组播调试工具

可以看到组播接收区收到了两条消息,一条是PC端发往组播的消息,一条是回环的消息。

总结

本文介绍了在W5500芯片上实现UDP组播的原理、应用场景及回环测试方法,并通过实战代码展示了其具体实现过程。 下一篇文章将聚焦DNS例程,讲解其工作原理及实现方法,帮助大家更深入地理解网络通信。敬请期待!

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板