Concepts First
- UDP server: UDP has no connections — the server simply binds a socket to a port and exchanges datagrams with anyone.
- Datagram: each UDP send/receive is one complete packet with preserved boundaries, unlike the TCP byte stream.
- recvfrom / sendto: UDP functions carry the peer's address, so you know who sent it and where to reply.
- Echo: the example returns received data verbatim to the sender.
Example Overview
This page covers the UDP echo server part of the wifi_udp example in the official Bouffalo SDK (examples/wifi/sta/wifi_udp/wifi_udp_echo.c):
socket(AF_INET, SOCK_DGRAM, 0)creates a UDP socket;bind()binds0.0.0.0:port;- loops
recvfrom()to receive datagrams, prints the source IP and content, thensendto()echoes back; - the shell command
wifi_udp_echo <port>starts the server;Ctrl+Cexits and prints statistics. - Related reference: UDP client and broadcast/multicast have no standalone examples; the tutorial provides self-written UDP client, UDP broadcast and UDP multicast.
Operation Steps
Open a terminal and enter the SDK UDP example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/wifi/sta/wifi_udpBoth Ai-M61 and Ai-M62 use bl616:
make CHIP=bl616 BOARD=bl616dkHold BOOT, briefly press EN/RST to enter download mode, then flash:
make flash CHIP=bl616 COMX=/dev/ttyUSB0Serial tool at 2000000 baud. Wait for bouffalolab />, connect to the router, then start the UDP echo server on port 3365:
wifi_sta_connect Your_SSID 12345678
wifi_udp_echo 3365On the PC, send datagrams to the module with netcat in UDP mode; the module echoes them back verbatim:
nc -uv 192.168.1.3 3365Code Execution Flow
The complete UDP server flow from boot to echo:
APIs Used by the Example
socket(AF_INET, SOCK_DGRAM, 0)
Creates a UDP socket. SOCK_DGRAM (datagram) is the key difference from TCP.
Parameters:
AF_INET: IPv4 familySOCK_DGRAM: connectionless datagram socket
Return: >= 0 handle; < 0 on failure
bind(sock, addr, len)
Binds the socket to a local port (the example uses 0.0.0.0:3365); datagrams to that port then arrive on this socket.
Parameters:
sock: socket handleaddr:sockaddr_inwithhtons(port)andINADDR_ANY
Return: 0 on success; -1 on failure
recvfrom(sock, buf, len, 0, from, fromlen)
Blocks until a datagram arrives and writes the sender's address into from.
Parameters:
sock: socket handlebuf/len: receive buffer and length (1024 in the example)from/fromlen: sender address
Return: bytes received; < 0 on error
sendto(sock, buf, len, 0, to, tolen)
Sends a datagram to the given address; for echo, pass the from from recvfrom back.
Parameters:
sock: socket handleto/tolen: destination address
Return: bytes sent; < 0 on error
Complete Code
The full wifi_udp_echo.c source, identical to the official example (examples/wifi/sta/wifi_udp). Collapsed by default; click to expand:
📜 Click to expand wifi_udp/main.c full code
/****************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include "wifi_mgmr_ext.h"
#include "bflb_irq.h"
#include "bflb_uart.h"
#include "rfparam_adapter.h"
#include "board.h"
#include "shell.h"
#ifndef BL602
#include "fhost_api.h"
#include "wifi_mgmr.h"
#endif
#include "async_event.h"
#include "mm.h"
#define DBG_TAG "MAIN"
#include "log.h"
struct bflb_device_s *gpio;
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define WIFI_STACK_SIZE (1536)
#define TASK_PRIORITY_FW (16)
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static struct bflb_device_s *uart0;
extern void shell_init_with_task(struct bflb_device_s *shell);
extern void wifi_event_handler(async_input_event_t ev, void *priv);
#ifdef BL602
extern void wifi_task_create(void);
extern int fhost_init(void);
extern int wifi_mgmr_task_start(void);
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Functions
****************************************************************************/
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);
}
void wifi_event_handler(async_input_event_t ev, void *priv)
{
uint32_t code = ev->code;
switch (code) {
case CODE_WIFI_ON_INIT_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE\r\n", __func__);
wifi_mgmr_task_start();
} break;
case CODE_WIFI_ON_MGMR_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE\r\n", __func__);
} break;
case CODE_WIFI_ON_SCAN_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE\r\n", __func__);
wifi_mgmr_sta_scanlist();
} break;
case CODE_WIFI_ON_CONNECTED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED\r\n", __func__);
void mm_sec_keydump();
mm_sec_keydump();
} break;
case CODE_WIFI_ON_GOT_IP: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP\r\n", __func__);
LOG_I("[SYS] Memory left is %d Bytes\r\n", kfree_size(0));
} break;
case CODE_WIFI_ON_DISCONNECT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STARTED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STOPPED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STA_ADD: {
LOG_I("[APP] [EVT] [AP] [ADD] %lld\r\n", xTaskGetTickCount());
} break;
case CODE_WIFI_ON_AP_STA_DEL: {
LOG_I("[APP] [EVT] [AP] [DEL] %lld\r\n", xTaskGetTickCount());
} break;
default: {
LOG_I("[APP] [EVT] Unknown code %u \r\n", code);
}
}
}
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;
}
LOG_I("PHY RF init success!\r\n");
tcpip_init(NULL, NULL);
xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);
vTaskStartScheduler();
while (1) {
}
}📜 Click to expand wifi_udp_echo.c full code
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <lwip/api.h>
#include <lwip/arch.h>
#include <lwip/opt.h>
#include <lwip/inet.h>
#include <lwip/errno.h>
#include <netdb.h>
#include "shell.h"
#include "utils_getopt.h"
#include "bflb_mtimer.h"
// clang-format off
uint32_t recv_buf[2 * 1024] = {0};
// clang-format on
shell_sig_func_ptr abort_exec;
uint64_t recv_len = 0;
int sock = -1;
static void test_close(int sig)
{
if (sock) {
closesocket(sock);
}
abort_exec(sig);
if (recv_len > 0) {
printf("Total send data=%lld\r\n", recv_len);
}
}
#define PING_USAGE \
"wifi_udp_echo [port]\r\n" \
"\t port: local listen port, default port 5001\r\n"
static void wifi_test_udp_echo_init(int argc, char **argv)
{
abort_exec = shell_signal(SHELL_SIGINT, test_close);
printf("udp server task start ...\r\n");
char *port;
struct sockaddr_in udp_addr, remote_addr;
socklen_t addr_len;
if (argc < 2) {
printf("%s", PING_USAGE);
return;
}
/* get port number (argv[1] if present) */
if (argc > 1) {
port = argv[1];
} else {
port = "5001";
}
memset(&recv_buf[0], 0, sizeof(recv_buf));
while (1) {
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("udp create socket error\r\n");
return;
}
udp_addr.sin_family = AF_INET;
udp_addr.sin_port = htons(atoi(port));
udp_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(udp_addr.sin_zero), 0, sizeof(udp_addr.sin_zero));
printf("Server ip Address : %s:%s\r\n", udp_addr.sin_addr.s_addr, port);
if (bind(sock, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr)) != 0) {
printf("udp bind falied!\r\n");
closesocket(sock);
return;
}
printf("udp bind port success!\r\n");
printf("Press CTRL-C to exit.\r\n");
recv_len = 0;
while (1) {
recv_len = recvfrom(sock, recv_buf, 1024, 0, (struct sockaddr *)&remote_addr, &addr_len);
printf("recv from %s\r\n", inet_ntoa(remote_addr.sin_addr));
printf("recv:%s \r\n", recv_buf);
sendto(sock, recv_buf, recv_len, 0, (struct sockaddr *)&remote_addr, addr_len);
}
closesocket(sock);
return;
}
}
#ifdef CONFIG_SHELL
#include <shell.h>
int cmd_wifi_udp_echo(int argc, char **argv)
{
wifi_test_udp_echo_init(argc, argv);
return 0;
}
SHELL_CMD_EXPORT_ALIAS(cmd_wifi_udp_echo, wifi_udp_echo, wifi udp test);
#endifFAQ
nc -uv cannot connect / no echo
Confirm the module and PC are on the same subnet and wifi_sta_connect succeeded (got IP). UDP has no connection — netcat's "Connection succeeded" only means the local socket is ready; send several packets (e.g. echo hi | nc -uv 192.168.1.3 3365) and check after the module receives them.
Cannot receive my own broadcast
This page is unicast echo. For subnet-wide broadcast or multicast, see UDP Broadcast and UDP Multicast; broadcast requires the SO_BROADCAST option.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

