全部例程

W55MH32 UDP通信测试

W55MH32

更新于 2026年9月23日

本篇总结

使用 W55MH32 的 TOE 引擎实现 UDP 数据回环测试。

🔑 KEIL MDK、UART调试、硬件TOE引擎、UDP、DHCP

硬件平台:本例程基于 W55MH32L-EVB 开发板运行。

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB

本示例演示使用 W55MH32 的 TOE 引擎实现 UDP 数据回环测试。核心是基于 Sn_SR 寄存器状态机的 loopback_udps() 函数,在 SOCK_CLOSED → SOCK_UDP 状态间切换,通过 recvfrom()/sendto() 收发数据并自动获取对端地址,实现无需连接的 UDP 数据回环。

前置工具准备

开始本例程前,请确认以下工具已安装:

UDP 协议简介

UDP(User Datagram Protocol)是一种无连接的、不可靠的传输层协议。与 TCP 不同,UDP 不需要建立连接,直接发送数据报文,具有开销小、延迟低的特点。UDP 不保证数据到达、不保证顺序、不保证完整性,但传输效率高,适合实时音视频、DNS 查询、SNMP 等对实时性要求高但对可靠性要求不严格的场景。

  • 无连接:无需三次握手,直接发送数据报文
  • 不可靠:不保证数据到达,不保证顺序,无重传机制
  • 高效率:无连接建立开销,头部仅 8 字节(TCP 为 20 字节)
  • 支持广播/组播:可向多个目标同时发送数据
  • recvfrom()/sendto():收发数据时自动获取/指定对端地址
对比项UDPTCP
连接方式无连接面向连接(三次握手)
可靠性不可靠,无重传可靠,自动重传
头部开销8 字节20 字节
传输效率高较低(确认/重传开销)
Socket状态SOCK_UDPSOCK_INIT/ESTABLISHED等
收发APIrecvfrom/sendtorecv/send

W55MH32 的 UDP 优势

W55MH32 的 TOE 引擎硬件支持 UDP 协议,UDP 报文的封装、校验、分片等全部在硬件内部完成。用户只需调用 socket(sn, Sn_MR_UDP, port, 0) 打开 UDP Socket,然后通过 recvfrom()/sendto() 收发数据,无需关心 UDP 协议细节。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W55MH32 处于同一网段。PC 端需运行 UDP 测试程序。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W55MH32 │ │ PC │
│UDP Server │ │SocketTester│
│ IP: DHCP │ │UDP Client │
│port:5000 │ │ │
└───────────┘ └───────────┘
↑ ↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:W55MH32 作为 UDP 回环服务器,PC 端发送 UDP 数据并接收回环

工程结构

工程位于 SDK 内 1.SDK\ModuleDemo\WZTOE\6.UDP\,核心文件如下:

6.UDP/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 初始化 + UDP 回环主循环
    ├── Loopback/
    │   ├── loopback.c        ← loopback_udps() 状态机核心
    │   └── loopback.h
    ├── wiz_interface/
    │   ├── wiz_interface.c   ← DHCP / PHY 检测 / 网络初始化
    │   └── wiz_interface.h
    ├── uart/
    │   ├── bsp_uart.c        ← 调试串口 + printf 重定向
    │   └── bsp_uart.h
    └── delay/
        └── delay.c/h          ← SysTick 毫秒延时

步骤1:主循环运行UDP回环测试

文件:USER/main.c

while (1)
{
    loopback_udps(SOCKET_ID, ethernet_buf, local_port);
}

三个传参分别为:SOCKET ID、UDP 协议缓存数组、本地监听端口号。示例本地端口为 5000。主循环不断调用状态机函数,等待 UDP 数据报文到达并回环发送。

步骤2:UDP状态机

loopback_udps() 函数基于 getSn_SR(sn) 返回的 Socket 状态执行对应操作。UDP 模式状态简单,只有 SOCK_CLOSED 和 SOCK_UDP 两个状态:

Socket状态执行操作
SOCK_CLOSED打开 UDP Socket,绑定端口,进入 SOCK_UDP
SOCK_UDPrecvfrom() 接收数据并获取对端地址,sendto() 回环发送

文件:USER/Loopback/loopback.c | 函数:loopback_udps()

int32_t loopback_udps(uint8_t sn, uint8_t *buf, uint16_t port)
int32_t loopback_udps(uint8_t sn, uint8_t *buf, uint16_t port)
{
    int32_t  ret;
    uint16_t size, sentsize;
    uint8_t  destip[4];
    uint16_t destport;

    switch (getSn_SR(sn))
    {
    case SOCK_UDP:
        if ((size = getSn_RX_RSR(sn)) > 0)
        {
            if (size > DATA_BUF_SIZE)
                size = DATA_BUF_SIZE;
            ret      = recvfrom(sn, buf, size, destip, (uint16_t *)&destport);
            buf[ret] = 0x00;
            printf("recv form[%d.%d.%d.%d][%d]: %s\r\n", destip[0], destip[1], destip[2], destip[3], destport, buf);
            if (ret <= 0)
            {
#ifdef _LOOPBACK_DEBUG_
                printf("%d: recvfrom error. %ld\r\n", sn, ret);
#endif
                return ret;
            }
            size     = (uint16_t)ret;
            sentsize = 0;
            while (sentsize != size)
            {
                ret = sendto(sn, buf + sentsize, size - sentsize, destip, destport);
                if (ret < 0)
                {
#ifdef _LOOPBACK_DEBUG_
                    printf("%d: sendto error. %ld\r\n", sn, ret);
#endif
                    return ret;
                }
                sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
            }
        }
        break;
    case SOCK_CLOSED:
#ifdef _LOOPBACK_DEBUG_
        // printf("%d:UDP loopback start\r\n",sn);
#endif
        if ((ret = socket(sn, Sn_MR_UDP, port, 0x00)) != sn)
            return ret;
#ifdef _LOOPBACK_DEBUG_
        printf("%d:Opened, UDP loopback, port [%d]\r\n", sn, port);
#endif
        break;
    default:
        break;
    }
    return 1;
}

状态机核心:SOCK_CLOSED 时调用 socket(sn, Sn_MR_UDP, port, 0) 打开 UDP Socket 并绑定端口;SOCK_UDP 时调用 recvfrom() 接收数据并自动获取对端 IP 和端口,然后 sendto() 将数据回环发送给对端。UDP 无需建立连接,状态机比 TCP 简单得多。

recvfrom() / sendto() — UDP 收发 API

recvfrom(sn, buf, size, destip, &destport) 接收 UDP 数据报文,同时将发送方的 IP 地址和端口号写入 destip 和 destport。sendto(sn, buf, size, destip, destport) 向指定 IP 和端口发送 UDP 数据。这两个函数是 UDP 编程的核心——每次收发都携带对端地址,无需维护连接状态。

如果你想自定义

  • 改监听端口 → 修改 main.c 中 local_port 的值
  • 主动发送 UDP 数据 → 在 SOCK_UDP 状态中直接调用 sendto(),指定目标 IP 和端口
  • 支持广播 → 将目标 IP 设为 255.255.255.255 或子网广播地址
  • 改用其他 Socket 编号 → 修改 SOCKET_ID 宏(W55MH32 TOE 支持 0-7 共 8 个 Socket)

运行验证

打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),观察开发板串口输出。UDP Socket 打开后会打印监听提示:

W55MH32 UDP example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
DHCP running
DHCP success!
====================================================================================================
 W55MH32 network configuration : DHCP
 MAC         : 00:08:DC:00:0E:9A
 IP          : 192.168.1.6
 Subnet Mask : 255.255.255.0
 Gateway     : 192.168.1.1
 DNS         : 192.168.1.1
====================================================================================================

0:Opened, UDP loopback, port [5000]

然后打开 SocketTester,设置为 UDP 模式,输入 W55MH32 的 IP 地址(192.168.1.30)和端口号(5000),点击"Connect"。向 W55MH32 发送 UDP 数据,即可收到回环数据,验证 UDP 通信正常。

W55MH32 串口输出 — UDP 回环初始化(PHY 链路 + DHCP + UDP Socket 打开)
WIZ UartTool 串口输出 + SocketTester UDP 客户端 — 数据回环测试

常见问题

Q: UDP和TCP有什么区别

UDP 无连接、不可靠但高效,无需三次握手,头部仅 8 字节。TCP 面向连接、可靠传输,通过三次握手建立连接,头部 20 字节。UDP 适合实时音视频、DNS 查询等场景,TCP 适合文件传输、网页浏览等场景。

Q: UDP数据丢失怎么办

UDP 不保证数据可靠传输,丢包由应用层处理。常见方案:1) 应用层添加序号和 ACK 确认机制;2) 对丢失不敏感的场景(如音视频)直接忽略;3) 如需可靠性建议使用 TCP。W55MH32 硬件会自动丢弃校验错误的 UDP 报文。

Q: recvfrom和recv有什么区别

recvfrom() 用于 UDP,接收数据同时获取发送方 IP 和端口(通过 destip 和 destport 参数)。recv() 用于 TCP,已建立连接无需获取对端地址。UDP 使用 recvfrom/sendto,TCP 使用 recv/send。

Q: UDP支持广播吗

支持。将 sendto() 的目标 IP 设为 255.255.255.255(全局广播)或子网广播地址(如 192.168.1.255),即可向网络中所有设备发送 UDP 广播报文。广播常用于设备发现、服务通告等场景。

Q: UDP Socket需要Keepalive吗

不需要。Keepalive 是 TCP 连接的保活机制,UDP 无连接概念,不存在"连接失效"问题。UDP Socket 打开后一直处于 SOCK_UDP 状态,可随时收发数据,无需保活探测。

总结

本文基于 W55MH32 硬件 TCP/IP 协议栈实现了 UDP 数据回环测试:

  • UDP 协议:无连接、不可靠但高效,头部仅 8 字节,适合实时性要求高的场景
  • 核心函数:loopback_udps() 基于 Sn_SR 状态机,SOCK_CLOSED → SOCK_UDP 两状态切换
  • 收发 API:recvfrom() 接收数据并获取对端地址,sendto() 向指定地址发送数据
  • 无需连接:UDP 无需三次握手,Socket 打开后即可收发,状态机比 TCP 简单
  • 支持广播:将目标 IP 设为 255.255.255.255 即可发送 UDP 广播报文

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板

Andy

W5500 技术支持专家