全部例程

W55MH32作为TCP服务器

W55MH32

更新于 2026年9月28日

本篇总结

使用 W55MH32 的 TOE 引擎实现 TCP 服务器模式,被动等待客户端连接进行数据回环测试。

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

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

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

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

前置工具准备

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

TCP 服务器与客户端

TCP 通信分为服务器端和客户端两种角色。服务器端被动等待客户端的连接请求,客户端主动发起连接。建立连接后,双方均可收发数据。TCP 服务器通过 listen() 进入监听状态,等待客户端 connect() 请求,三次握手成功后建立连接。

对比项TCP 服务器TCP 客户端
连接方向被动等待连接主动发起连接
关键APIlisten()connect()
端口要求固定端口(如8080)源端口可任意
SOCK_LISTEN有(监听状态)无
目标地址不需要需指定服务器IP+端口

W55MH32 TCP 服务器特点

W55MH32 的 TOE 引擎支持 8 个独立 Socket,每个 Socket 均可配置为 TCP 服务器。服务器模式下调用 socket() 打开 Socket 后,调用 listen() 进入监听状态,等待客户端连接。三次握手由 TOE 硬件自动完成,用户只需轮询 Sn_SR 状态。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W55MH32 处于同一网段。PC 端作为 TCP 客户端主动连接开发板。

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

工程结构

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

3.TCP_Server/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 初始化 + TCP 服务器主循环
    ├── Loopback/
    │   ├── loopback.c        ← loopback_tcps() 状态机核心
    │   └── 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

KeepAlive 的时间单元为 5 秒,设置 6 个单元则每 30 秒发送一次 KeepAlive 报文。服务器模式下 Keepalive 尤为重要——当客户端异常断电或断网时,服务器无法感知连接已断开,Keepalive 可以检测并清理这些无效连接。

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

文件:USER/main.c

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

三个传参分别为:SOCKET ID、TCP协议缓存数组、本地监听端口号。示例本地端口为 8080。主循环不断调用状态机函数,等待客户端连接。

步骤3:TCP Server状态机

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

Socket状态执行操作
SOCK_CLOSED配置端口并打开TCP Socket,进入 SOCK_INIT
SOCK_INIT调用 listen() 进入监听状态 SOCK_LISTEN
SOCK_LISTEN等待客户端连接,无操作
SOCK_ESTABLISHED连接已建立,清除中断,收发数据回环
SOCK_CLOSE_WAIT客户端主动断开,调用 disconnect() 断开

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

int32_t loopback_tcps(uint8_t sn, uint8_t *buf, uint16_t port)
{
    int32_t ret;
    uint16_t size = 0, sentsize = 0;

    switch (getSn_SR(sn))
    {
    case SOCK_ESTABLISHED:                          // 连接已建立
        if (getSn_IR(sn) & Sn_IR_CON)               // 连接成功中断
        {
            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_LISTEN:                               // 监听状态,等待连接
        break;
    case SOCK_INIT:                                 // Socket已打开
        listen(sn);                                 // 进入监听状态
        break;
    case SOCK_CLOSED:                               // Socket未打开
        close(sn);
        socket(sn, Sn_MR_TCP, port, 0x00);          // 打开TCP Socket,绑定端口
        break;
    default:
        break;
    }
    return 1;
}

状态机核心:SOCK_CLOSED 时打开 Socket 并绑定固定端口,SOCK_INIT 时调用 listen() 进入监听,SOCK_LISTEN 等待客户端连接,SOCK_ESTABLISHED 时收发数据,SOCK_CLOSE_WAIT 时断开连接。与客户端模式的关键区别是 listen() 替代 connect()。

listen() — TCP 服务器监听

listen(sn) 使 Socket n 从 SOCK_INIT 状态进入 SOCK_LISTEN 监听状态,开始等待客户端的连接请求。当客户端发起 connect() 时,TOE 硬件自动完成三次握手,Socket 状态变为 SOCK_ESTABLISHED。一个 Socket 只能接受一个客户端连接,多客户端需使用多个 Socket。

如果你想自定义

  • 改监听端口 → 修改 main.c 中 local_port 的值
  • 支持多客户端 → 参考《多个 Socket 作为 TCP 服务器》,使用 8 个 Socket 同时监听
  • 改用其他 Socket 编号 → 修改 SOCKET_ID 宏(W55MH32 TOE 支持 0-7 共 8 个 Socket)

运行验证

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

W55MH32 TCP Server 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 server loopback start
0:Socket opened
0:Listen, TCP server loopback, port [8080]

然后打开 SocketTester,设置为 TCP Client 模式,输入 W55MH32 的 IP 地址(192.168.1.30)和端口号(8080),点击"Connect"连接服务器。连接成功后,向服务器发送数据即可进行回环测试。

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

常见问题

Q: TCP服务器和TCP客户端有什么区别

TCP 服务器被动等待连接,调用 listen() 进入监听状态,使用固定端口。TCP 客户端主动发起连接,调用 connect() 连接服务器,源端口可任意。服务器有 SOCK_LISTEN 监听状态,客户端没有。

Q: 一个Socket能接受多个客户端连接吗

不能。W55MH32 的一个 Socket 只能接受一个客户端连接。如果需要支持多客户端同时连接,需要使用多个 Socket 同时监听相同或不同端口,参见《多个 Socket 作为 TCP 服务器》例程。

Q: Keepalive 在服务器模式下有什么用

当客户端异常断电或断网时,服务器无法感知连接已断开,Socket 会一直停留在 SOCK_ESTABLISHED 状态。Keepalive 定期发送探测报文,若未收到回复则判定连接失效,自动关闭 Socket 释放资源。

Q: 客户端连接不上服务器怎么办

排查步骤:1) 确认 PC 和 W55MH32 同一网段;2) 确认 SocketTester 中输入的 IP 和端口正确;3) 检查串口是否打印 "Opened, TCP Server, port [8080]";4) 关闭 PC 端防火墙。

Q: SOCK_LISTEN 和 SOCK_ESTABLISHED 状态有什么区别

SOCK_LISTEN 是监听状态,Socket 已打开并调用 listen(),等待客户端连接请求,此时不能收发数据。SOCK_ESTABLISHED 是连接已建立状态,三次握手完成,可以正常收发数据。

总结

本文基于 W55MH32 硬件 TCP/IP 协议栈实现了 TCP 服务器模式通信:

  • 服务器 vs 客户端:服务器被动等待连接(listen),客户端主动发起连接(connect),服务器使用固定端口
  • 核心函数:loopback_tcps() 基于 Sn_SR 状态机实现 SOCK_CLOSED→SOCK_INIT→SOCK_LISTEN→SOCK_ESTABLISHED 全流程
  • Keepalive:服务器模式下尤为重要,可检测客户端异常断开并清理无效连接
  • 单 Socket 限制:一个 Socket 只能接受一个客户端连接,多客户端需使用多 Socket
  • 状态机模式:所有 Socket 编程本质都是"读取 getSn_SR() → 根据状态执行操作"的轮询模式

下载本章例程

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

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

Andy

W5500 技术支持专家