Concepts First
- UDP client: the device that actively "throws" datagrams at a server. UDP needs no connection —
sendtowith a destination address is enough. - Datagram: one complete packet per send/receive with preserved boundaries; delivery and order are not guaranteed, which suits real-time apps that tolerate occasional loss.
- sendto / recvfrom: sending carries the destination, receiving carries the sender; since there is no connection, the address must be stated explicitly each time.
- UDP port: the server listens on a fixed port; the client's source port is assigned by the system.
Example Overview
The SDK has no standalone UDP client example; this self-written example is built on the wifi_tcp skeleton (its networking matches the official wifi_udp example, both based on lwIP sockets):
- after getting an IP, creates
udp_client_task; socket(AF_INET, SOCK_DGRAM, 0)creates a UDP socket;- sends
hello from ai-m6xtoUDP_SERVER_IP:6000every second and prints the reply; - change
UDP_SERVER_IP/UDP_SERVER_PORTat the top of the file to retarget. - Related reference: the official
wifi_udpexample demonstrates the server/echo side (see UDP Server).
Operation Steps
The SDK has no standalone UDP client example (wifi_udp only ships an echo server), so this page is written on the wifi_tcp skeleton (marked self-written). First enter the directory:
cd examples/wifi/sta/wifi_tcpOverwrite main.c in the example directory with the self-written one below (change UDP_SERVER_IP to your server’s IP):
Both 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. After connecting to the router the program automatically sends hello from ai-m6x to UDP_SERVER_IP:6000 every second and prints the server’s reply. On the PC, run a UDP echo service first (e.g. nc -u -l 6000) to observe.
wifi_sta_connect Your_SSID 12345678Code Execution Flow
The complete UDP client flow from boot to send/receive:
APIs Used by the Example
socket(AF_INET, SOCK_DGRAM, 0)
Creates a UDP socket.
Parameters:
AF_INET: IPv4 familySOCK_DGRAM: datagram (UDP) socket
Return: >= 0 handle; < 0 on failure
sendto(sock, buf, len, 0, to, tolen)
Sends a datagram to the given address.
Parameters:
sock: socket handlebuf/len: data and lengthto/tolen: destination (server IP and port)
Return: bytes sent; < 0 on error
recvfrom(sock, buf, len, 0, from, fromlen)
Blocks until a datagram arrives and returns the sender's address. The example uses it to wait for the server's reply.
Parameters:
sock: socket handlefrom/fromlen: sender address
Return: bytes received; < 0 on error
Complete Code
The self-written main.c below (built on the SDK wifi_tcp skeleton; not an SDK file). Collapsed by default; click to expand:
📜 Click to expand self-written udp_client main.c full code
/*
* Self-written example: UDP client (based on lwIP sockets)
* Usage:
* 1. Overwrite examples/wifi/sta/wifi_tcp/main.c with this file;
* 2. Change UDP_SERVER_IP to your server's IP;
* 3. make CHIP=bl616 BOARD=bl616dk && make flash CHIP=bl616 COMX=/dev/ttyUSB0;
* 4. Run wifi_sta_connect <SSID> <password> on the serial shell; the program sends/receives automatically.
*/
#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_SERVER_IP "192.168.1.2"
#define UDP_SERVER_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_client_task(void *param)
{
int sock;
struct sockaddr_in server;
char send_buf[] = "hello from ai-m6x";
char recv_buf[128];
socklen_t addr_len = sizeof(server);
/* Wait for Wi-Fi to get an 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;
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(UDP_SERVER_PORT);
server.sin_addr.s_addr = inet_addr(UDP_SERVER_IP);
LOG_I("UDP client send to %s:%d\r\n", UDP_SERVER_IP, UDP_SERVER_PORT);
while (1) {
int ret = sendto(sock, send_buf, strlen(send_buf), 0,
(struct sockaddr *)&server, sizeof(server));
if (ret < 0) {
LOG_E("sendto failed\r\n");
} else {
LOG_I("send %d bytes\r\n", ret);
}
ret = recvfrom(sock, recv_buf, sizeof(recv_buf) - 1, 0,
(struct sockaddr *)&server, &addr_len);
if (ret >= 0) {
recv_buf[ret] = '\0';
LOG_I("recv %d bytes: %s\r\n", ret, recv_buf);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
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_client_task, "udp client", 1024, NULL, 11, NULL);
vTaskStartScheduler();
while (1) {
}
}FAQ
The server receives nothing
Confirm the module got an IP (log shows Got IP); UDP_SERVER_IP must be the server's actual IP and you must rebuild/flash after changing it; the server's firewall may block UDP — test with nc -u -l 6000 on the same subnet first.
recvfrom blocks forever and never prints a reply
UDP delivery is not guaranteed; if the server never replies, recvfrom waits forever. Set a receive timeout (setsockopt(SO_RCVTIMEO)) or comment out the receive part while debugging the send path.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

