概念先知道
- UDP 广播(Broadcast):把数据报发给“同一局域网内的所有设备”,目标地址是
255.255.255.255(全网段广播)或192.168.1.255这样的网段广播地址。 - 适用场景:局域网设备发现(“谁在线?”)、无中心的服务公告、局域网校时等。广播不会跨路由器转发。
- SO_BROADCAST:出于安全考虑,lwIP 默认不允许发送广播,必须先用
setsockopt(SOL_SOCKET, SO_BROADCAST)打开。 - 接收广播:要接收广播/回复,需要把套接字绑定到对应端口,并同样打开
SO_BROADCAST。
例程功能简介
SDK 无 UDP 广播例程,本页自编示例在 wifi_tcp 例程骨架上编写:
- 拿到 IP 后创建
udp_broadcast_task; - 打开
SO_BROADCAST选项并绑定本地6000端口; - 每 2 秒向
255.255.255.255:6000广播hello broadcast; - 同时接收局域网内的广播/回复并打印,验证“一发多收”。
- 同族参考:向固定一组设备发送用 UDP 组播,点对点用 UDP 客户端。
操作步骤
SDK 没有 UDP 广播例程,本页在 wifi_tcp 例程骨架上编写(标注自编示例)。先进入目录:
cd examples/wifi/sta/wifi_tcp用下面的自编 main.c 覆盖例程目录里的 main.c:
统一填写 bl616:
make CHIP=bl616 BOARD=bl616dk按住 BOOT 短按 EN/RST 进入下载模式后烧录:
make flash CHIP=bl616 COMX=/dev/ttyUSB0串口助手波特率 2000000,连接路由器后程序自动开始:每 2 秒向 255.255.255.255:6000 广播一次,并打印收到的广播/回复。可在同一 Wi-Fi 下的另一台电脑上运行 nc -u -l 6000 观察。
wifi_sta_connect Your_SSID 12345678代码执行流程
UDP 广播从启动到收发的完整流程如下:
例程调用的 API 介绍
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))
打开广播发送权限,opt = 1 使能。不做这一步,sendto 广播地址会失败。
参数:
sock:套接字句柄SO_BROADCAST:选项名&opt:int,1表示允许
返回值:0 成功;-1 失败
bind(sock, addr, len)
把套接字绑定到本地端口(示例 0.0.0.0:6000),这样才能收到发往该端口的广播与回复。
参数:
sock:套接字句柄addr:sockaddr_in,端口htons(6000)、地址INADDR_ANYlen:地址结构长度
返回值:0 成功;-1 失败
sendto / recvfrom(sock, buf, len, 0, addr, len)
发送时目标地址填广播地址 255.255.255.255:6000;接收时 recvfrom 返回发送方地址,方便区分是哪台设备发来的。
参数:
sock:套接字句柄buf/len:数据与长度addr/len:目标(发送)/ 来源(接收)地址
返回值:实际收/发字节数;< 0 出错
完整代码
以下为自编示例 main.c(基于 SDK wifi_tcp 例程骨架编写,非 SDK 自带文件),默认折叠,点击展开:
📜 点击展开 自编 udp_broadcast main.c 完整代码
/*
* 自编示例:UDP 广播(基于 lwIP socket)
* 使用方法:
* 1. 用本文件覆盖 examples/wifi/sta/wifi_tcp/main.c;
* 2. make CHIP=bl616 BOARD=bl616dk && make flash CHIP=bl616 COMX=/dev/ttyUSB0;
* 3. 串口执行 wifi_sta_connect <SSID> <密码>,程序自动广播/接收。
*/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include <string.h>
#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include "wifi_mgmr_ext.h"
#include "fhost_api.h"
#include "wifi_mgmr.h"
#include "bflb_irq.h"
#include "bflb_uart.h"
#include "rfparam_adapter.h"
#include "async_event.h"
#include "mm.h"
#include "board.h"
#include "shell.h"
#define DBG_TAG "MAIN"
#include "log.h"
#define UDP_BROADCAST_PORT 6000
static volatile uint32_t wifi_state = 0;
static struct bflb_device_s *uart0;
extern void shell_init_with_task(struct bflb_device_s *shell);
void wifi_event_handler(async_input_event_t ev, void *priv)
{
switch (ev->code) {
case CODE_WIFI_ON_GOT_IP:
wifi_state = 1;
LOG_I("Got IP\r\n");
break;
case CODE_WIFI_ON_DISCONNECT:
wifi_state = 0;
LOG_I("WiFi disconnected\r\n");
break;
default:
break;
}
}
static void udp_broadcast_task(void *param)
{
int sock;
int opt = 1;
struct sockaddr_in local, bcast, remote;
socklen_t addr_len = sizeof(remote);
char send_buf[] = "hello broadcast";
char recv_buf[128];
/* 等待 Wi-Fi 拿到 IP */
while (!wifi_state) {
vTaskDelay(pdMS_TO_TICKS(200));
}
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
LOG_E("create socket failed\r\n");
vTaskDelete(NULL);
return;
}
/* 允许发送广播 */
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0) {
LOG_E("set SO_BROADCAST failed\r\n");
}
/* 绑定本地端口,用于接收广播与回复 */
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(UDP_BROADCAST_PORT);
local.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0) {
LOG_E("bind failed\r\n");
}
/* 广播地址:255.255.255.255 代表当前网段全部设备 */
memset(&bcast, 0, sizeof(bcast));
bcast.sin_family = AF_INET;
bcast.sin_port = htons(UDP_BROADCAST_PORT);
bcast.sin_addr.s_addr = inet_addr("255.255.255.255");
LOG_I("UDP broadcast start, port %d\r\n", UDP_BROADCAST_PORT);
while (1) {
int ret = sendto(sock, send_buf, strlen(send_buf), 0,
(struct sockaddr *)&bcast, sizeof(bcast));
if (ret < 0) {
LOG_E("sendto broadcast failed\r\n");
} else {
LOG_I("broadcast send %d bytes\r\n", ret);
}
ret = recvfrom(sock, recv_buf, sizeof(recv_buf) - 1, 0,
(struct sockaddr *)&remote, &addr_len);
if (ret >= 0) {
recv_buf[ret] = '\0';
LOG_I("recv %d bytes from %s: %s\r\n",
ret, inet_ntoa(remote.sin_addr), recv_buf);
}
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
static void wifi_start_firmware_task(void *param)
{
LOG_I("Starting wifi ...\r\n");
async_register_event_filter(EV_WIFI, wifi_event_handler, NULL);
wifi_task_create();
LOG_I("Starting fhost ...\r\n");
fhost_init();
vTaskDelete(NULL);
}
int main(void)
{
board_init();
uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
if (0 != rfparam_init(0, NULL, 0)) {
LOG_I("PHY RF init failed!\r\n");
return 0;
}
tcpip_init(NULL, NULL);
xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);
xTaskCreate(udp_broadcast_task, "udp bcast", 1024, NULL, 11, NULL);
vTaskStartScheduler();
while (1) {
}
}FAQ
sendto 广播地址报错
确认 setsockopt(SOL_SOCKET, SO_BROADCAST) 执行成功;lwIP 默认禁止广播发送,没有打开该选项会返回错误。
其他设备收不到广播
广播只在同一局域网(同一路由器/交换机)内传播,不同网段收不到;路由器开启“AP 隔离”时客户端之间互相隔离,需关闭该功能。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

