LwIP RAW API 实现UDP多播收发

news/2024/5/18 12:35:52 标签: udp, 网络协议, 网络, LwIP, UDP多播, UDP组播

LwIP_RAW_API_UDP_0">LwIP RAW API 实现UDP多播收发实现

1、初始化

static struct udp_pcb *multicast_pcb = NULL;
static ip_addr_t mutlcast_send_ip;
static ip_addr_t mutlcast_recv_ip;

static void udp_recv_multicast(void *arg, struct udp_pcb *pcb, struct pbuf *p,
    const ip_addr_t *addr, u16_t port);

static void udp_multicast_init(void)
{
    err_t err;

    if (multicast_pcb != NULL) return;

    multicast_pcb = udp_new();
    if (multicast_pcb == NULL)
    {
        LOG_LINE("udp_pcb申请失败");
        return;
    }

    IP4_ADDR(&mutlcast_send_ip, 239, 255, 255, 255);  /* 设置发送多播地址 */

    IP4_ADDR(&mutlcast_recv_ip, 239, 255, 255, 0);  /* 设置加入的多播接收地址 */

     /* 加入多播组 */
    err = igmp_joingroup(IP_ADDR_ANY, &mutlcast_recv_ip);
    if (err != ERR_OK)
    {
        LOG_LINE("加入多播组失败");
        goto free_udp_pcb;
    }

    err = udp_bind(multicast_pcb, IP_ADDR_ANY, 7770);   /* 绑定端口 */
    if (err != ERR_OK)
    {
        if (err == ERR_USE)
        {
            LOG_LINE("IP地址或端口已经被使用");
        }
        LOG_LINE("绑定IP、端口失败");
        goto free_udp_pcb;
    }

    udp_recv(multicast_pcb, udp_recv_multicast, NULL);
    
    LOG_LINE("组播初始化");
    return;
free_udp_pcb:
    udp_remove(multicast_pcb);
}

2、多播发送

int udp_multicast_send(const void *psrc, uint32_t src_len, uint16_t port)
{
    struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, src_len, PBUF_POOL);
    if (p == NULL)
    {
        LOG_LINE("pbuf申请失败");
        return -1;
    }
    pbuf_take(p, psrc, src_len);
    udp_sendto(multicast_pcb, p, &mutlcast_send_ip, port);
    pbuf_free(p);  /* 释放pbuf */
    return 0;
}

3、多播接收

static char recv_multicast_buf[1024] = {0};
void udp_recv_multicast(void *arg, struct udp_pcb *pcb, struct pbuf *p,
    const ip_addr_t *addr, u16_t port)
{
    struct pbuf *q;
    int recv_count = 0;
    struct ip4_addr_fmt {
        uint32_t addr1 : 8;
        uint32_t addr2 : 8;
        uint32_t addr3 : 8;
        uint32_t addr4 : 8;
    };

    for (q = p; q != NULL; q = p->next)
    {
        if (q->len > sizeof(recv_multicast_buf))
        {
            memcpy(recv_multicast_buf, q->payload, sizeof(recv_multicast_buf));
            LOG_LINE("数据溢出, 截断接收");
            return;
        }
        else 
        {
            if (recv_count < sizeof(recv_multicast_buf))
            {
                rt_memcpy(&recv_multicast_buf[recv_count], q->payload, q->len);
                recv_count += q->len;
            }
            else
            {
                LOG_LINE("数据溢出, 截断接收");
                return;
            }
        }
    }
    // uint32_t ip = addr->addr;
    struct ip4_addr_fmt *ip = (struct ip4_addr_fmt *)addr;
    LOG_LINE("multicast recv from %d.%d.%d.%d/%d, msg %s", 
            ip->addr1, ip->addr2, ip->addr3, ip->addr4, port, recv_multicast_buf);
}

通过UDP接收回调函数接收数据保存到buffer。
这里只是将接收的消息打印出来。

测试

组播发送测试:
打开网络调试助手,设置好监听端口号,板子程序通过什么端口号发送,这里就设置为相应的端口号。
在这里插入图片描述
前面初始化程序发送设置的多播组是239.255.255.255 ,往7777端口发送数据,所以这里设置端口号为7777

测试程序:

static char fmt_buf[10] = {0};
static uint16_t test_count = 0;
void btn_long_press_start(void *p_btn)
{
    struct Button *btn = (struct Button *)p_btn;
    switch (btn->button_id)
    {
        case BTN_ID_SYS_TEST:  /* 测试键 */

            break;
        case BTN_ID_CARD_OUT:  /* 强制退卡键 */
            rt_snprintf(fmt_buf, sizeof(fmt_buf), "test %d", ++test_count);
            udp_multicast_send(fmt_buf, rt_strlen(fmt_buf), 7777);
            LOG_LINE("退卡键长按 %s", fmt_buf);
            rt_memset(fmt_buf, 0, sizeof(fmt_buf));
            break;
        default:
            LOG_LINE("don't have this key");
            break;
    }
}

在这里插入图片描述
组播接收测试:
网络调试助手设置组播地址和远程地址、端口
在这里插入图片描述
板子程序接收数据加入的多播组是239.255.255.0,端口号是7770 ,IP地址是192.168.57.101

点击网络调试助手发送,串口调试助手打印出接收的数据
在这里插入图片描述

参考:

网络编程:用UDP通信实现组播通信(多播)_udp组播通信_qq_42343682的博客-CSDN博客

UDP局域网内广播消息_udp广播网段192.168.0.255_changeyourmind的博客

STM32F4板子使用LWIP进行组播收发数据的完整过程,附代码_lwip组播_纵横千里,捭阖四方的博客-CSDN博客


http://www.niftyadmin.cn/n/442697.html

相关文章

高考状元、通用语言和轰趴-UMLChina建模知识竞赛第4赛季第4轮

DDD领域驱动设计批评文集 欢迎加入“软件方法建模师”群 《软件方法》各章合集 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答。 只要最先答对前3题&#xff0c;即可获得本轮优胜。第4题为附加题&#xff0c;对错不影响获奖&#xff0c…

2个苹果.

"如果妈妈和你一起出去玩&#xff0c;我们渴了&#xff0c;又没带水&#xff0c;而你的小书包里恰巧有两个苹果&#xff0c;你会怎么做呢?”一位母亲这样问五岁的儿子。 小孩歪着头思考片刻&#xff0c;说&#xff1a;“我会把两个苹果都咬一口。” 这位母亲本想像其他…

Spring - Bean的6种作用域

1、Bean作用域问题2、作用域定义2.1、Bean的6种作用域singleton 单例模式prototype 原型作用域request 请求作用域session 会话作用域application 全局作用域&#xff08;了解&#xff09;websocket 单例作用域 vs 全局作用域 2.设置作用域 1、Bean作用域问题 通过一个案例来看…

在 Quarkus 中的使用 Mutiny 进行响应式编程

在 Quarkus 中使用 Mutiny - 事件驱动的 Java 响应式编程库 本教程介绍在 Quarkus 中使用事件驱动的 Mutiny 响应式编程库 以应对异步系统开发中的挑战。 概述 Mutiny 是一个&#xff08;Reactive Programming&#xff09;响应式编程库, 事件是 Mutiny 的设计核心&#xff0…

python基础-函数专题

hello&#xff0c;这里是GUIDM 这一篇是python基础函数篇&#xff0c;希望这张内容对您能有所帮助。 函数-代码段。 功能单一 复用性 创建一个函数三要素&#xff1a; 1、函数名–命名规范:顾名思义、驼峰法&#xff08;大驼峰【定义类名时】ClassName、小驼峰getName&#xff…

c++系列之string类的常用接口函数

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; string string时表示字符串的字符类 //使用 string类包含#include 头文件 以及…

4.pixi.js编写的塔防游戏(类似保卫萝卜)-a星寻路

游戏说明 一个用pixi.js编写的h5塔防游戏&#xff0c;可以用electron打包为exe&#xff0c;支持移动端&#xff0c;也可以用webview控件打包为app在移动端使用 环境说明 cnpm6.2.0 npm6.14.13 node12.22.7 npminstall3.28.0 yarn1.22.10 npm config list electron_mirr…

如何翻译 Markdown 文件?-2-几种商业及开源解决方案介绍

背景 近期在搭建英文博客-<e-whisper.com>, 需要对现有的所有中文 Markdown 翻译为英文。 需求如下&#xff1a; 将 Markdown 文件从中文 (zh-CN) 翻译为英文 (en)翻译后要保留 Markdown 的完整格式部分 Markdown block 不需要翻译&#xff0c;如&#xff1a;front-ma…