Overview
With the board acting as a UDP server, it listens on a fixed port, receives UDP datagrams from any client and echoes them back. A UDP server needs no connection handling — one socket serves all clients, so the code is simpler than a TCP server, commonly used for LAN broadcasting/multi-device reporting. This tutorial demonstrates: listening on port 7878, printing the source IP of received data and sending it back unchanged.
In plain words: the UDP server is the board running a parcel collection window — receiving at the 7878 "door number" (port): whoever sends (source IP and port), everything is taken in, opened for a look, wrapped up and sent back as-is (echo). Unlike a TCP server, it doesn't need to register every visitor (no accept, no connection maintenance) — one window serves all clients at once, which is why the code is simpler.
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_server; the code can be found directly in your local SDK.
Open a terminal and enter the official udp_server example project directory:
cd ~/Ai-Thinker-WB2/applications/protocols/socket/udp_server
Note:
cdis the “change directory” command, entering the official example project; all subsequentmakecommands must run in this directory.
Open udp_server/main.c and change the SSID/password at the top (same as Connect Wi-Fi):
#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"
#define UDP_SERVER_PORT 7878
💡
UDP_SERVER_PORT 7878is the listening port (the server’s “door number”); the computer-side client must use the same port to find the right door. The server and client must be on the same LAN.
Open udp_server/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_server/udp_server/main.c).
Code highlights:
| Code | Purpose |
|---|---|
udp_server_init(NULL, 7878) |
Creates the socket and binds/listens on port 7878; only a manned window can receive packages |
recvfrom(fd, buf, 512, MSG_DONTWAIT, &addr, &len) |
Non-blocking receive that also yields the source address (IP + port); no package, keep waiting for the next round without stalling |
inet_ntoa(u_sockaddr.sin_addr.s_addr) |
Prints the client IP; translates the binary address into human-readable numbers |
sendto(fd, buf, len, 0, &addr, len) |
Echoes back to the source client; sends it back as-is so the other side knows you got it |
strstr(udp_buf, "close") |
On receiving close, replies then exits; when the other side says shut the door, shut it |
udp_server_deinit() |
Frees server resources; without it, the next start may report the port is in use |
💡 vs the TCP server: UDP needs no accept — one socket directly sends/receives for all clients;
recvfromfillsu_sockaddr(source address) alongside the data, and you reuse it as-is when echoing.MSG_DONTWAITnon-blocking +vTaskDelay(50)polling is the official example’s approach.
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_server.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.
After flashing, the board automatically restarts and runs. The serial (baud rate 921600) prints GOT IP; note the board’s IP.
Set the computer network debugging assistant to UDP Client mode:
| Setting | Value |
|---|---|
| Target IP | Board IP (e.g. 192.168.1.100) |
| Port | 7878 |
Send hello wb2; the board serial prints:
udp server task run
192.168.1.50:hello wb2
The computer assistant receives the echo hello wb2. Send close; the board replies server close connect and the server task exits.
The serial printing udp server task run and “client IP:content” (e.g. 192.168.1.50:hello wb2), plus the computer assistant receiving the echo hello wb2 means success. If the board doesn’t respond after sending, first confirm the board is online (you saw GOT IP first), the computer and board are on the same LAN, and the port is 7878 — see the FAQ at the end.
💡 A UDP server naturally supports multiple clients: the computer, a phone and another board can all send data at the same time — all received and echoed normally, without interference (no per-client connection needed).
API Summary for This Tutorial
udp_server_init(s_ip, s_port)
Creates a socket and binds a listening port (project wrapper; pass NULL as s_ip to listen on all addresses).
Parameters:
s_ip: listen address;NULLlistens on all addressess_port: listen port (7878in the official example)
Return: socket descriptor on success; -1 on failure
socket(domain, type, proto)
Creates a socket (SOCK_DGRAM datagram type).
Parameters:
domain:AF_INET(IPv4)type:SOCK_DGRAM(UDP datagram)proto: pass0
Return: socket descriptor on success; -1 on failure
bind(fd, addr, len)
Binds a port (the wrapper's underlying layer).
Parameters:
fd: socket descriptoraddr: local address (INADDR_ANYlistens on all addresses)len: address length
Return: 0 on success; negative error code on failure
recvfrom(fd, buf, len, flags, addr, addrlen)
Receives data and gets the source address (MSG_DONTWAIT non-blocking).
Parameters:
fd: socket descriptorbuf: receive bufferlen: buffer lengthflags: optionallyMSG_DONTWAIT(non-blocking)addr: output parameter, source addressaddrlen: address length
Return: bytes received on success; <= 0 when non-blocking and no data; negative on failure
sendto(fd, buf, len, flags, addr, addrlen)
Sends data to a specified address.
Parameters:
fd: socket descriptorbuf: data bufferlen: buffer lengthflags: flags, pass0addr: target addressaddrlen: address length
Return: bytes sent on success; negative on failure
inet_ntoa(addr)
Converts an IP address to a dotted-decimal string.
Parameters:
addr: network-byte-order IP (in_addr)
Return: dotted-decimal string (not thread-safe)
pvPortMalloc / vPortFree(size / ptr)
FreeRTOS dynamic memory allocation / release.
Parameters:
size: bytes to allocateptr: pointer to free (returned bypvPortMalloc)
Return: pvPortMalloc: pointer on success, NULL on failure; vPortFree: none
📌
struct sockaddr_inkey fields:sin_addr.s_addr(client IP),sin_port(client port); whenrecvfromis non-blocking,ret <= 0means no data yet — pair it withvTaskDelaypolling.
Full Code
Below is the complete udp_server/main.c source, identical to the official example (applications/protocols/socket/udp_server/udp_server/main.c):
📜 Click to expand the full udp_server/main.c code
/**
* @file main.c
* @author your name (you@domain.com)
* @brief
* @version 0.1
* @date 2022-10-13
*
* @copyright Copyright (c) 2022
*
*/
#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_server.h"
#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"
#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_server_task
*
* @param arg
*/
static void udp_server_task(void* arg)
{
int socket_fd;
int ret = 0;
socket_fd = udp_server_init(NULL, UDP_SERVER_PORT);
struct sockaddr_in u_sockaddr;
int socke_len = sizeof(struct sockaddr_in);
char* udp_buf = pvPortMalloc(512);
while (1) {
memset(udp_buf, 0, 512);
ret = recvfrom(socket_fd, udp_buf, 512, MSG_DONTWAIT, (struct sockaddr*)&u_sockaddr, (socklen_t*)&socke_len);
if (ret>0) {
blog_info("%s:%s\r\n", inet_ntoa(u_sockaddr.sin_addr.s_addr), udp_buf);
ret = sendto(socket_fd, udp_buf, strlen(udp_buf), 0, (struct sockaddr*)&u_sockaddr, socke_len);
if (strstr(udp_buf, "close")!=NULL) {
ret = sendto(socket_fd, "server close connect", strlen("server close connect"), 0, (struct sockaddr*)&u_sockaddr, socke_len);
goto __exit;
}
}
vTaskDelay(50/portTICK_PERIOD_MS);
}
__exit:
vPortFree(udp_buf);
udp_server_deinit();
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 server task
xTaskCreate(udp_server_task, "udp_server_task", 2048, 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
⚠️ Board doesn't respond after the computer client sends
Cause: port mismatch, wrong target IP, or the board didn't get an IP
Fix: confirm the computer-side target IP is the board's IP and the port is 7878; confirm the serial first printed GOT IP and udp server task run
⚠️ Data received but echoes get lost
Cause: UDP itself is unreliable; packet loss under weak networks
Fix: send a few times consecutively to verify; switch to TCP when the business demands reliability
⚠️ Receive buffer too small, data truncated
Cause: udp_buf is only 512 bytes
Fix: keep single packets within 512 bytes; for larger data enlarge both pvPortMalloc and the recvfrom length (UDP single-packet limit 1460)
⚠️ Port in use error after reboot
Cause: the previous connection wasn't fully released
Fix: wait a few seconds before restarting; or call udp_server_deinit() and recreate the task
⚠️ 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_server/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 client sends any content, the board serial prints the client IP and content and echoes it back — the UDP server is verified.

