全部例程

W55MH32作为TCP客户端

W55MH32

更新于 2026年9月28日

本篇总结

使用 W55MH32 的 TOE 引擎实现 TCP 客户端模式,连接服务器进行数据回环测试,支持 Keepalive 保活机制。

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

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

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

本示例演示使用 W55MH32 的 TOE 引擎实现 TCP 客户端模式,主动连接服务器进行数据回环测试。核心是基于 Sn_SR 寄存器状态机的 loopback_tcpc() 函数,在 SOCK_CLOSED → SOCK_INIT → SOCK_ESTABLISHED 状态间切换,实现连接、收发、断开全流程,并支持 Keepalive 保活机制。

前置工具准备

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

TCP 协议简介

TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议,用于在网络中可靠地传输数据。TCP 是互联网协议族中的核心协议之一,通常与 IP 协议一起使用,形成套接字通信。TCP 通过三次握手建立连接、四次挥手断开连接,提供可靠性(超时重传、快速重传)、流量控制(滑动窗口)和拥塞控制等机制。

  • 面向连接:传输数据前通过三次握手建立连接
  • 可靠性:数据丢失或出错时自动重传
  • 流量控制:滑动窗口机制调节发送速度
  • 全双工通信:两个方向同时传输数据
  • Keepalive:Sn_KPALVTR 寄存器,5秒为单位,检测空闲连接是否有效

W55MH32 的 TCP 优势

W55MH32 片内集成了完整的硬件 TCP/IP 协议栈,TCP 的三次握手、数据确认、重传、滑动窗口等机制全部在 TOE 硬件内部完成。MCU 只需通过 SPI 读写 Socket 寄存器,调用 connect()/send()/recv() 等 API 即可实现 TCP 通信,无需在软件中实现 TCP 协议栈。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W55MH32 处于同一网段。PC 端需运行 TCP 服务器程序。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W55MH32 │ │ PC │
│TCP Client │ │SocketTester│
│ IP: DHCP │ │TCP Server │
└───────────┘ └───────────┘
↑ ↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:W55MH32 作为 TCP 客户端主动连接 PC 上的 TCP 服务器

工程结构

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

2.TCP_Client/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 初始化 + TCP 客户端主循环
    ├── Loopback/
    │   ├── loopback.c        ← loopback_tcpc() 状态机核心
    │   └── 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:开启TCP Keepalive功能

文件:USER/main.c

/* Enable keepalive, Parameter 2 is the keep alive time, with a unit of 5 seconds */
setSn_KPALVTR(SOCKET_ID, 6); // 30s keepalive

在 W55MH32 中,KeepAlive 的时间单元为 5 秒,设置 6 个单元则每 30 秒发送一次 KeepAlive 报文。Keepalive 用于检测长时间空闲的连接是否仍然有效,避免假连接。

步骤2:主循环运行TCP Client回环测试

文件:USER/main.c

while (1)
{
    loopback_tcpc(SOCKET_ID, ethernet_buf, dest_ip, dest_port);
}

四个传参分别为:SOCKET ID、TCP协议缓存数组、目标服务器IP地址、目标服务器端口号。示例目标地址为 192.168.1.20:8080。主循环不断调用状态机函数,由状态机内部根据 Socket 状态执行对应操作。

步骤3:TCP Client状态机

loopback_tcpc() 函数基于 getSn_SR(sn) 返回的 Socket 状态执行对应操作:

Socket状态执行操作
SOCK_CLOSED配置端口并打开TCP Socket,进入 SOCK_INIT
SOCK_INIT调用 connect() 连接服务器,成功后进入 SOCK_ESTABLISHED
SOCK_ESTABLISHED清除连接中断,激活Keepalive,接收数据并回环发送
SOCK_CLOSE_WAIT服务器主动断开时,调用 disconnect() 彻底断开

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

int32_t loopback_tcpc(uint8_t sn, uint8_t *buf, uint8_t *destip, uint16_t destport)
{
    int32_t  ret;
    uint16_t size = 0, sentsize = 0;
    static uint16_t any_port = 50000;

    switch (getSn_SR(sn))
    {
    case SOCK_ESTABLISHED:                          // 连接已建立
        if (getSn_IR(sn) & Sn_IR_CON)               // 连接成功中断
        {
            send(sn, (uint8_t *)"", 1);              // 激活Keepalive
            setSn_IR(sn, Sn_IR_CON);                // 清除中断标志
        }
        if ((size = getSn_RX_RSR(sn)) > 0)          // 有数据到达
        {
            if (size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
            ret = recv(sn, buf, size);               // 接收数据
            buf[size] = 0x00;
            // 回环发送
            while (size != sentsize)
            {
                ret = send(sn, buf + sentsize, size - sentsize);
                if (ret < 0) { close(sn); return ret; }
                sentsize += ret;
            }
        }
        break;
    case SOCK_CLOSE_WAIT:                           // 服务器主动断开
        disconnect(sn);
        break;
    case SOCK_INIT:                                 // Socket已打开,等待连接
        connect(sn, destip, destport);              // 连接服务器
        break;
    case SOCK_CLOSED:                               // Socket未打开
        close(sn);
        socket(sn, Sn_MR_TCP, any_port++, 0x00);    // 打开TCP Socket
        if (any_port == 0xffff) any_port = 50000;
        break;
    default:
        break;
    }
    return 1;
}

状态机核心:SOCK_CLOSED 时打开 Socket(端口自动递增),SOCK_INIT 时 connect() 连接服务器,SOCK_ESTABLISHED 时收发数据并激活 Keepalive,SOCK_CLOSE_WAIT 时断开连接。TOE 硬件自动维护 TCP 协议栈,用户只需轮询 getSn_SR() 并根据状态做相应处理。

getSn_SR(sn) — WIZnet Socket 状态寄存器

getSn_SR(sn) 读取 TOE 硬件中 Socket n 的状态寄存器(Sn_SR),返回值指示该 Socket 当前状态——SOCK_CLOSED、SOCK_INIT、SOCK_ESTABLISHED、SOCK_CLOSE_WAIT 等。所有基于 Socket 的编程本质上都是"读取 getSn_SR() → 根据状态执行对应操作"的状态机模式。

端口自动递增

W55MH32 异常断开时服务器不知道客户端掉线,继续使用上次端口连接会被拒绝。因此连接失败后端口自动加1(从50000开始)。若服务器要求固定端口,则不能使用此机制。

如果你想自定义

  • 改目标服务器地址 → 修改 main.c 中 dest_ip 和 dest_port 的值
  • 提高吞吐量 → 通过 Sn_TXBUF_SIZE 和 Sn_RXBUF_SIZE 重新分配 Socket 缓存大小,同时增大 DATA_BUF_SIZE
  • 改用其他 Socket 编号 → 修改 SOCKET_ID 宏(W55MH32 TOE 支持 0-7 共 8 个 Socket)

运行验证

打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),观察开发板串口输出。当服务器未开启时,会一直打印打开 Socket 和连接服务器提示消息:

W55MH32 TCP Client 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:TCP client loopback start
0:Socket opened
0:Try to connect to the 192.168.1.20 : 8080
0:Connected to - 192.168.1.20 : 8080

然后打开 SocketTester,设置为 TCP Server 模式,选择 PC 的 IP 地址和端口号(8080),点击"Listen"开始侦听。W55MH32 连接成功后,向其发送数据即可进行回环测试。

W55MH32 串口输出 — TCP 客户端初始化(PHY 链路 + DHCP + TCP 连接)
WIZ UartTool 串口输出 + SocketTester TCP 服务器 — 数据回环测试

常见问题

Q: 为什么W55MH32连接服务器时端口会自动变化

W55MH32 异常断开时,服务器端并不知道客户端已掉线,继续使用上次连接的端口会被服务器拒绝。因此连接失败后端口自动加1(从50000开始)。若服务器要求固定端口,需修改代码取消自动递增。

Q: Keepalive 如何配置和激活

通过 setSn_KPALVTR(sn, 6) 设置 Keepalive 时间(6×5秒=30秒)。激活方式:在 socket 成功连接服务器后(SOCK_ESTABLISHED 状态),调用 send() 发送一条数据即可激活 Keepalive 功能。

Q: 如何提高TCP通信吞吐量

两种方式:1) 通过 Sn_TXBUF_SIZE 和 Sn_RXBUF_SIZE 寄存器重新分配 socket 缓存大小;2) 增大 TCP 协议缓存数组(DATA_BUF_SIZE)。两者需要同时调整。

Q: SOCK_CLOSE_WAIT 状态是什么意思

当服务器主动断开连接时,Socket 进入 SOCK_CLOSE_WAIT 半关闭状态,此时仍可进行关闭前最后的数据传输。调用 disconnect() 后 Socket 彻底断开,状态变为 SOCK_CLOSED。

Q: PC端ping不通W55MH32怎么办

排查步骤:1) 检查PC和W55MH32是否同一网段;2) 确认网线连接正确,尝试PC直连;3) 回读IP、子网掩码、网关寄存器值是否正确;4) 关闭PC端防火墙。

总结

本文基于 W55MH32 硬件 TCP/IP 协议栈实现了 TCP 客户端模式通信:

  • TCP协议:面向连接、可靠传输,通过三次握手建立连接、四次挥手断开连接
  • 核心函数:loopback_tcpc() 基于 Sn_SR 状态机实现 SOCK_CLOSED→SOCK_INIT→SOCK_ESTABLISHED 全流程
  • Keepalive:通过 Sn_KPALVTR 寄存器设置保活时间(5秒/单元),连接后发送数据激活
  • 端口递增:连接失败时端口自动加1避免被服务器拒绝,固定端口场景需修改代码
  • 吞吐优化:调整 Sn_TXBUF_SIZE/Sn_RXBUF_SIZE 和 DATA_BUF_SIZE 提升数据吞吐量

下载本章例程

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

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

Andy

W5500 技术支持专家