鸿蒙LiteOS RK2206 Socket编程实战 UDP通信+LWIP原理全解析
B站 配套视频教程【鸿蒙 LiteOS 实战 15】LwIP socket API UDP通信 客户端
前言
在鸿蒙LiteOS(以瑞芯微RK2206为例)开发中,Socket网络编程是设备联网通信的核心技能,无论是设备与服务器数据交互、MQTT传输还是UDP广播控制,都离不开标准Socket接口与LWIP轻量级网络协议栈。
本文基于RK2206官方Demo源码,从零讲解Socket基础、阻塞通信特性、UDP协议原理,同时拆解LiteOS网络组件LWIP的底层逻辑,带你彻底掌握嵌入式设备的UDP客户端开发。
本文主要目标:
- 什么是Socket,如何写标准Socket程序
- 什么是阻塞通信,如何从日志观察阻塞
- UDP 协议通信原理与实战
- LiteOS 网络组件从哪里来(LWIP)
一、什么是Socket?标准Socket程序怎么写?
1. Socket 核心概念
Socket(套接字) 是计算机网络中进程间通信的端点 ,可以理解为网络通信的"插座":两个设备想要通信,必须各自创建一个Socket,通过IP地址+端口号唯一标识,然后基于Socket完成数据的发送与接收。
简单来说:Socket = IP地址 + 端口号,它屏蔽了底层网络协议的复杂细节,为上层应用提供统一的读写接口。
2. 标准Socket程序通用框架
无论Windows、Linux还是嵌入式LiteOS,标准Socket编程流程完全一致 ,分为TCP 和UDP 两种模式,本文重点讲UDP(无连接) 模式。
UDP Socket 标准编程流程(客户端)
1. 创建Socket → socket()
2. 配置服务器地址(IP+端口)
3. 发送数据 → sendto()
4. 接收数据 → recvfrom()
5. 关闭Socket → close()
对应本文代码核心实现
c
// 1. 创建UDP Socket(SOCK_DGRAM表示UDP协议)
int fd = socket(AF_INET, SOCK_DGRAM, 0);
// 2. 配置服务器地址
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET; // 地址族:IPv4
server_addr.sin_addr.s_addr = inet_addr(IP);// 服务器IP
server_addr.sin_port = htons(PORT); // 服务器端口(主机字节序转网络字节序)
// 3. 发送数据
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&server_addr, len);
// 4. 接收数据
recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr *)&server_addr, &len);
// 5. 关闭Socket
lwip_close(fd);
关键函数说明
socket(AF_INET, SOCK_DGRAM, 0):AF_INET:IPv4协议;SOCK_DGRAM:UDP数据报协议 (TCP对应SOCK_STREAM);- 返回值:Socket文件描述符(负数表示创建失败)。
htons():主机字节序转网络字节序(网络传输统一用大端序)。sendto()/recvfrom():UDP专用收发函数,无需建立连接,直接指定目标地址收发数据。
二、什么是阻塞通信?如何从日志观察阻塞?
1. 阻塞通信定义
阻塞通信 :当程序调用阻塞函数时,内核会挂起当前线程,直到函数执行完成(收到数据/超时/出错)才会继续执行后续代码。
简单理解:线程会"卡住"等待,不完成不往下走。
本文UDP代码中,recvfrom()就是典型的阻塞函数:
- 当服务器没有发送数据时,线程会停在
recvfrom()这一行,一直等待数据到来; - 只有收到数据、函数返回后,才会执行后续的
LOS_Msleep(1000)。
2. 阻塞通信的特点
- 编程简单,逻辑直观;
- 线程资源占用低(阻塞时内核不调度);
- 适合简单的同步通信场景(本文UDP客户端)。
3. 如何从日志观察阻塞?
结合本文代码,通过串口日志可以清晰看到阻塞行为:
# 正常收发日志(无阻塞等待)
[Send] RK2206 UDP Client msg: 1
[Recv] Server reply: hello
[Send] RK2206 UDP Client msg: 2
[Recv] Server reply: hello
# 服务器未回复时(阻塞现象)
[Send] RK2206 UDP Client msg: 3
# 这里会停顿!线程阻塞在recvfrom(),无任何日志输出
# 直到服务器发送数据,才会打印[Recv]
观察关键点:
- 发送完数据后,长时间没有接收日志 → 线程阻塞在
recvfrom(); - 一旦服务器回复,立即打印接收日志 → 阻塞解除,线程恢复执行。
扩展:非阻塞通信
如果不想让线程卡住,可以将Socket设置为非阻塞模式:
c
// 获取Socket当前状态
int flags = fcntl(fd, F_GETFL, 0);
// 设置为非阻塞
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
非阻塞模式下,recvfrom()无数据时会立即返回-1,不会挂起线程。
三、UDP协议通信原理与实战(基于本文代码)
1. UDP 协议核心原理
UDP(User Datagram Protocol,用户数据报协议) 是无连接、不可靠、轻量级的传输层协议,核心特点:
- 无需建立连接:不像TCP需要三次握手,直接发送数据报;
- 不可靠传输:不保证数据一定到达,不保证顺序;
- 面向数据报:数据按包发送,包与包之间独立;
- 速度快、开销小:适合视频、直播、传感器实时数据传输。
2. UDP 与 TCP 核心区别
| 特性 | UDP | TCP |
|---|---|---|
| 连接性 | 无连接 | 面向连接(三次握手) |
| 可靠性 | 不可靠 | 可靠(重传、确认) |
| 传输效率 | 高 | 低 |
| 适用场景 | 实时通信、广播、组播 | 文件传输、可靠通信 |
3. 本文UDP客户端实战解析
本文代码是标准的LiteOS UDP客户端,完整实现了「WiFi联网→UDP循环收发」功能,核心逻辑拆解:
(1)等待WiFi联网(前置条件)
c
// 循环等待WiFi连接成功+获取到IP地址
while (udp_get_wifi_info(&g_wifiinfo) != 0)
{
LOS_Msleep(1000);
}
- 嵌入式设备必须先联网(获取IP),才能进行Socket通信;
GetLinkedInfo()是RK2206 WiFi驱动接口,获取连接状态和IP。
(2)UDP循环收发
c
while (1)
{
// 1. 发送数据到服务器
sprintf(buf, "RK2206 UDP Client msg: %d \r\n", cnt++);
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&server_addr, len);
// 2. 阻塞等待服务器回复
count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr *)&server_addr, &len);
LOS_Msleep(1000);
}
- 每秒发送一条自定义消息到指定服务器;
- 阻塞等待服务器回复,收到后打印数据;
- 全程无连接,断电、断网重连后可直接恢复通信。
(3)测试方法
-
修改代码中3个核心参数:
c#define OC_SERVER_IP "192.168.111.61" // 电脑端服务器IP #define SERVER_PORT 20108 // 服务器端口 #define CLIENT_LOCAL_PORT 8888 // 本地端口 -
电脑打开网络调试助手,创建UDP服务器;
-
烧录程序到RK2206,WiFi联网后即可看到双向通信日志。

四、LiteOS网络组件从哪里来?LWIP协议栈全解析
1. 为什么嵌入式要用LWIP?
PC端的网络协议栈庞大复杂,占用大量内存,嵌入式设备(MCU、IoT芯片)资源有限,无法直接使用。
因此嵌入式领域通用LWIP(Light Weight IP) 轻量级网络协议栈:
- 开源、免费、体积小;
- 支持TCP/UDP/IP/ARP等完整网络协议;
- 内存占用极低,适合单片机、IoT设备;
- 鸿蒙LiteOS、FreeRTOS、RT-Thread全部内置LWIP。
2. 本文代码中的LWIP
代码开头的头文件,全部来自LWIP协议栈:
c
#include "lwip/udp.h"
#include "lwip/ip_addr.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include "lwip/inet_chksum.h"
我们调用的socket()/sendto()/recvfrom(),本质是LWIP对外封装的标准POSIX接口,底层由LWIP实现网络数据的打包、发送、解析。
3. LWIP在LiteOS中的架构
应用层 → 标准Socket接口(sendto/recvfrom)
↓
LWIP协议栈 → 处理TCP/UDP/IP协议
↓
网卡驱动 → WiFi/以太网硬件驱动
↓
硬件层 → RK2206 WiFi模块
4. LiteOS中LWIP的核心作用
- 实现标准Socket API,让开发者像写Linux网络程序一样写嵌入式网络代码;
- 管理网络连接、IP地址、端口、数据缓存;
- 完成数据的封装与解包(IP头、UDP头、校验和);
- 与底层硬件驱动交互,实现数据的物理收发。
简单说:LWIP就是LiteOS的"网络心脏",没有它,嵌入式设备无法实现TCP/IP通信。
五、完整代码说明
本文提供的代码是RK2206鸿蒙LiteOS UDP客户端完整可运行代码,仅需修改3个参数即可直接使用:
- 服务器IP;
- 服务器端口;
- 本地端口。
代码特性:
- 开机自动启动(
APP_FEATURE_INIT); - 自动等待WiFi联网成功;
- 阻塞式UDP循环收发,1秒发送一次;
- 串口打印收发日志,方便调试。
六、总结
- Socket是网络通信的端点,嵌入式UDP Socket遵循「创建→配置地址→收发→关闭」标准流程;
- 阻塞通信是线程等待函数执行完成,通过串口日志可观察到"停顿"现象,编程简单;
- UDP是无连接、轻量级协议,适合实时性要求高的场景,无需建立连接直接收发数据;
- LWIP是LiteOS内置的轻量级网络协议栈,是嵌入式设备联网的核心组件,提供标准Socket接口。
本文基于RK2206实战Demo,从基础到原理全覆盖,适合鸿蒙LiteOS、嵌入式网络编程新手学习,替换IP和端口即可直接用于项目开发。