Overview
UDP is a connectionless, unreliable transport protocol: no connection is established and delivery isn't guaranteed, but it has low overhead and low latency — suited to scenarios demanding real-time performance with tolerance for a few lost packets (e.g. sensor status pushes, LAN control, audio/video streaming). This tutorial demonstrates: sending data to a target server and looping to receive replies.
In plain words: UDP is like shipping a package — write the delivery address (target IP and port) and toss it straight into the parcel locker (send), no need to first confirm the other side is there. The advantage is speed: no waiting for a connection, send and go; the disadvantage is no guarantee: the package may get lost (no resend if lost), arrive out of order, or arrive duplicated. So it suits scenarios like "sensor status pushes" where losing one message is fine because the next one arrives right away.
This tutorial is based on the official Ai-Thinker SDK (Ai-Thinker-Open/Ai-Thinker-WB2, version
release_bl_iot_sdk_1.6.40) exampleapplications/protocols/socket/udp_cllient(note the official directory name is spelledudp_cllient); the code can be found directly in your local SDK.
Open a terminal and enter the official udp_cllient example project directory:
cd ~/Ai-Thinker-WB2/applications/protocols/socket/udp_cllient
Note:
cdis the “change directory” command, entering the official example project; all subsequentmakecommands must run in this directory.
💡 The official directory is named
udp_cllient(two l’s); the code lives in theudp_clientsub-project directory.
Open udp_client/main.c and change the SSID/password and server address at the top:
#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"
#define UDP_SERVER_IP "127.0.0.0"
#define UDP_SERVER_PORT 7878
Change UDP_SERVER_IP to your computer’s LAN IP (e.g. 192.168.1.50), with the port (the “door number” on the network) matching your computer-side UDP debug tool.
💡 The official default
127.0.0.0is a placeholder address; flashing without changing it fails to connect. Your computer’s IP can be found withipconfig(Windows) /ifconfig(Linux/Mac).
Open udp_client/main.c. The full code for this step has been moved to the end of this page:
📜 Full Code — in the “Full Code” section below, collapsed by default — click to expand, identical to the official example (
applications/protocols/socket/udp_cllient/udp_client/main.c).
Code highlights:
| Code | Purpose |
|---|---|
udp_client_init(ip, port) |
Creates the UDP socket and initializes (wrapped in udp_client.h); no creation, no shipping |
udp_client_connect(socketfd) |
UDP has no connection; this step records the target address (returns 0 on success); like writing the delivery address on the envelope |
udp_client_send(socketfd, "hell udp server") |
Sends data (delivery not guaranteed); tossing the package out, not responsible if lost |
udp_client_receive(socketfd, buf) |
Receives replies (non-blocking polling); if nobody replies, keep doing other things instead of waiting idle |
udp_client_send(socketfd, "client close") |
Notifies the server before exiting; saying goodbye before leaving, whether it arrives is luck |
udp_client_deinit(socketfd) |
Frees socket resources; not freeing keeps occupying memory |
💡 UDP vs TCP differences: no three-way handshake —
connectonly records the target address; no connection state — the client isn’t notified when the server goes offline; the maximum datagram is about 1472 bytes (Ethernet MTU 1500 minus IP/UDP headers).
Build in the project directory:
make -j8
Note:
makeis the “build” command, turning code into firmware (the program flashed into the board) the board can run;-j8builds with 8 parallel cores, faster.
On success a firmware build_out/udp_client.bin is generated.
Keep the board connected via USB, confirm the serial device, and flash:
make flash p=/dev/ttyUSB0 b=921600
Note:
make flashis the “flash” command, writing the compiled firmware into the board. Afterp=comes the serial device (often/dev/ttyUSB0on Linux,COM3-like on Windows — use your computer’s actual one),b=921600is the flash baud rate (serial transfer speed), keep the default.
⏳ During flashing, press and hold the EN button on the board when prompted to enter download mode; wait for the progress bar to complete — that means the flash succeeded.
Prepare the computer side first: set the network debugging assistant to UDP Server mode, listening on port 7878 (must match UDP_SERVER_PORT).
After flashing, the board automatically restarts and runs. The serial (baud rate 921600, the “speech speed” of serial data — both ends must match) prints:
[APP] [EVT] GOT IP 5
udp client task run
udp_client_task:udp client connect OK
udp client send OK
The computer debug assistant receives hell udp server. Reply hello wb2 to the board; the serial prints:
udp_client_task:udp receive data:hello wb2
Send close to the board; it prints udp receive data:close and exits the task (sending client close to the computer then ending).
udp client connect OK and udp client send OK appearing, plus the computer assistant receiving hell udp server and the serial printing the reply hello wb2 means success. If the computer doesn’t receive data, first confirm the board is online (you saw GOT IP), UDP_SERVER_IP was changed to your computer’s LAN IP, and the computer-side listening port matches UDP_SERVER_PORT, see the FAQ at the end.
API Summary for This Tutorial
udp_client_init(server_ip, port)
Creates the UDP socket and initializes (project wrapper).
Parameters:
server_ip: target IP stringport: target port
Return: socket descriptor on success; -1 on failure
udp_client_connect(socket_fd)
Records the target address (UDP has no real connection, project wrapper).
Parameters:
socket_fd: socket descriptor
Return: 0 on success; negative error code on failure
udp_client_send(socket_fd, data)
Sends a datagram (project wrapper).
Parameters:
socket_fd: socket descriptordata: data to send
Return: bytes sent on success; <0 on failure
udp_client_receive(socket_fd, data)
Receives a datagram (project wrapper).
Parameters:
socket_fd: socket descriptordata: receive buffer
Return: bytes received on success; negative on failure
udp_client_deinit(socket_fd)
Closes the socket and frees resources (project wrapper).
Parameters:
socket_fd: socket descriptor
Return: none
sendto(fd, buf, len, flags, addr, addrlen)
Sends data to a specified address (the wrapper's underlying layer).
Parameters:
fd: socket descriptorbuf: data bufferlen: buffer lengthflags: flags, pass0addr: target address (struct sockaddr*)addrlen: address length
Return: bytes sent on success; negative on failure
recvfrom(fd, buf, len, flags, addr, addrlen)
Receives data from a specified address (the wrapper's underlying layer).
Parameters:
fd: socket descriptorbuf: receive bufferlen: buffer lengthflags: flags, pass0addr: output parameter, source addressaddrlen: address length
Return: bytes received on success; negative on failure
📌 UDP unreliability: data can be lost, reordered or duplicated — the business layer must add its own sequence numbers/checksums/retransmit mechanisms (like the ideas behind CoAP, QUIC); for scenarios demanding reliability, choose TCP.
Full Code
Below is the complete udp_client/main.c source, identical to the official example (applications/protocols/socket/udp_cllient/udp_client/main.c):
📜 Click to expand the full udp_client/main.c code
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <string.h>
#include <blog.h>
#include <aos/yloop.h>
#include <aos/kernel.h>
#include <lwip/sockets.h>
#include <lwip/tcpip.h>
#include <wifi_mgmr_ext.h>
#include <cli.h>
#include <hal_wifi.h>
#include <lwip/init.h>
#include "udp_client.h"
#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"
#define UDP_SERVER_IP "127.0.0.0"
#define UDP_SERVER_PORT 7878
static wifi_conf_t conf = {
.country_code = "CN",
};
/**
* @brief wifi_sta_connect
* wifi station mode connect start
* @param ssid
* @param password
*/
static void wifi_sta_connect(char* ssid, char* password)
{
wifi_interface_t wifi_interface;
wifi_interface = wifi_mgmr_sta_enable();
wifi_mgmr_sta_connect(wifi_interface, ssid, password, NULL, NULL, 0, 0);
}
/**
* @brief udp_client_task
*
* @param arg
*/
static void udp_client_task(void* arg)
{
blog_info("udp client task run\r\n");
int socketfd;
int ret = 0;
char* tcp_buff = pvPortMalloc(512);
memset(tcp_buff, 0, 512);
socketfd = udp_client_init(UDP_SERVER_IP, UDP_SERVER_PORT);
if (!udp_client_connect(socketfd)) {
blog_info("%s:udp client connect OK\r\n", __func__);
}
else goto __exit;
if (udp_client_send(socketfd, "hell udp server")<0) {
printf("udp client send fail\r\n");
goto __exit;
}
else
blog_info("udp client send OK\r\n");
while (1) {
ret = udp_client_receive(socketfd, tcp_buff);
if (ret>0) {
blog_info("%s:udp receive data:%s \r\n", __func__, tcp_buff);
if (strstr(tcp_buff, "close")) goto __exit;
memset(tcp_buff, 0, 512);
}
vTaskDelay(100/portTICK_PERIOD_MS);
}
__exit:
vPortFree(tcp_buff);
udp_client_send(socketfd, "client close");
udp_client_deinit(socketfd);
vTaskDelete(NULL);
}
/**
* @brief event_cb_wifi_event
* wifi connet ap event Callback function
* @param event
* @param private_data
*/
static void event_cb_wifi_event(input_event_t* event, void* private_data)
{
static char* ssid;
static char* password;
switch (event->code)
{
case CODE_WIFI_ON_INIT_DONE:
{
printf("[APP] [EVT] INIT DONE %lld\r\n", aos_now_ms());
wifi_mgmr_start_background(&conf);
}
break;
case CODE_WIFI_ON_MGMR_DONE:
{
printf("[APP] [EVT] MGMR DONE %lld\r\n", aos_now_ms());
//_connect_wifi();
wifi_sta_connect(ROUTER_SSID, ROUTER_PWD);
}
break;
case CODE_WIFI_ON_SCAN_DONE:
{
printf("[APP] [EVT] SCAN Done %lld\r\n", aos_now_ms());
// wifi_mgmr_cli_scanlist();
}
break;
case CODE_WIFI_ON_DISCONNECT:
{
printf("[APP] [EVT] disconnect %lld\r\n", aos_now_ms());
}
break;
case CODE_WIFI_ON_CONNECTING:
{
printf("[APP] [EVT] Connecting %lld\r\n", aos_now_ms());
}
break;
case CODE_WIFI_CMD_RECONNECT:
{
printf("[APP] [EVT] Reconnect %lld\r\n", aos_now_ms());
}
break;
case CODE_WIFI_ON_CONNECTED:
{
printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
}
break;
case CODE_WIFI_ON_PRE_GOT_IP:
{
printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
}
break;
case CODE_WIFI_ON_GOT_IP:
{
printf("[APP] [EVT] GOT IP %lld\r\n", aos_now_ms());
printf("[SYS] Memory left is %d Bytes\r\n", xPortGetFreeHeapSize());
//WiFi connection succeeded, create UDP client task
xTaskCreate(udp_client_task, (char*)"udp_client_task", 1024*2, NULL, 16, NULL);
}
break;
case CODE_WIFI_ON_PROV_SSID:
{
printf("[APP] [EVT] [PROV] [SSID] %lld: %s\r\n",
aos_now_ms(),
event->value ? (const char*)event->value : "UNKNOWN");
if (ssid)
{
vPortFree(ssid);
ssid = NULL;
}
ssid = (char*)event->value;
}
break;
case CODE_WIFI_ON_PROV_BSSID:
{
printf("[APP] [EVT] [PROV] [BSSID] %lld: %s\r\n",
aos_now_ms(),
event->value ? (const char*)event->value : "UNKNOWN");
if (event->value)
{
vPortFree((void*)event->value);
}
}
break;
case CODE_WIFI_ON_PROV_PASSWD:
{
printf("[APP] [EVT] [PROV] [PASSWD] %lld: %s\r\n", aos_now_ms(),
event->value ? (const char*)event->value : "UNKNOWN");
if (password)
{
vPortFree(password);
password = NULL;
}
password = (char*)event->value;
}
break;
case CODE_WIFI_ON_PROV_CONNECT:
{
printf("[APP] [EVT] [PROV] [CONNECT] %lld\r\n", aos_now_ms());
printf("connecting to %s:%s...\r\n", ssid, password);
wifi_sta_connect(ssid, password);
}
break;
case CODE_WIFI_ON_PROV_DISCONNECT:
{
printf("[APP] [EVT] [PROV] [DISCONNECT] %lld\r\n", aos_now_ms());
}
break;
default:
{
printf("[APP] [EVT] Unknown code %u, %lld\r\n", event->code, aos_now_ms());
/*nothing*/
}
}
}
static void proc_main_entry(void* pvParameters)
{
aos_register_event_filter(EV_WIFI, event_cb_wifi_event, NULL);
hal_wifi_start_firmware_task();
aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0);
vTaskDelete(NULL);
}
void main()
{
puts("[OS] Starting TCP/IP Stack...\r\n");
tcpip_init(NULL, NULL);
puts("[OS] proc_main_entry task...\r\n");
xTaskCreate(proc_main_entry, (char*)"main_entry", 1024, NULL, 15, NULL);
}FAQ & Troubleshooting
⚠️ Computer doesn't receive data
Cause: UDP_SERVER_IP wasn't changed (default 127.0.0.0 is a placeholder), port mismatch, or the computer's firewall blocks it
Fix: confirm the IP is the computer's LAN IP and the port matches; turn off the firewall or allow the UDP port
⚠️ Data received but occasionally lost
Cause: UDP itself is unreliable; packet loss is normal over weak Wi-Fi
Fix: add application-layer retransmission in the business; or switch to TCP
⚠️ Sending large packets fails
Cause: exceeds the UDP single-packet limit (MTU 1500 - 40 = 1460 bytes)
Fix: keep single packets under 1400 bytes; for large files use TCP or UDP fragmentation + reassembly
⚠️ After the server changes IP, the old address still receives data
Cause: the UDP socket wasn't re-connected to update the target address
Fix: call udp_client_connect again or recreate the socket when changing the target address
⚠️ Keeps printing Connecting, never GOT IP (can't connect to the router)
Cause: wrong SSID/password, the router is on 5GHz, or the signal is too weak
Fix: double-check ROUTER_SSID/ROUTER_PWD in udp_client/main.c match the router exactly; confirm the router is 2.4GHz (the board doesn't support 5GHz); try moving the board closer to the router
⚠️ Serial device not found / can't open
Cause: USB-to-serial driver not installed, insufficient permission, or the cable only charges and can't transfer data
Fix: on Linux check the device with lsusb/dmesg; if permission denied run sudo chmod 666 /dev/ttyUSB0; on Windows install the driver and check the COM port in Device Manager; try a data-capable cable
⚠️ Flashing keeps waiting / fails
Cause: download mode wasn't entered, wrong baud rate, or a wrong serial number
Fix: press and hold EN during flashing to enter download mode as prompted; change p=/dev/ttyUSB0 to your actual serial port; try another USB port or cable
Self-Check
The computer debug assistant receives hell udp server, and the board receives the reply data — the UDP client is verified.

