全部例程

W55MH32多个socket作为TCP服务器

W55MH32

更新于 2026年9月24日

本篇总结

使用 W55MH32 的 8 个硬件 Socket 作为 TCP 服务器,轮询切换监听同一端口(8000),最多接受 8 个客户端连接。

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

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

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

本示例演示使用 W55MH32 的 8 个硬件 Socket 作为 TCP 服务器,监听同一端口(8000)接受多个客户端连接进行数据回环测试。核心是主循环持续调用 multi_tcps_socket() 函数,函数内部通过静态变量 socket_sn 自增轮流切换 8 个 Socket,每个 Socket 独立维护 SOCK_CLOSED → SOCK_INIT → SOCK_LISTEN → SOCK_ESTABLISHED 状态机。

前置工具准备

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

硬件连接与拓扑

请注意:

测试需要 PC 端和 W55MH32 处于同一网段。PC 端作为 TCP 客户端,可建立多个连接(最多 8 个)到开发板。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W55MH32 │ │ PC │
│8x TCP Srv │ │SocketTester│
│Sock 0-7 │ │8x TCP Clt │
│ IP: DHCP │ │ │
│ port:8000 │ │ │
└───────────┘ └───────────┘
↑ ↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:W55MH32 的 8 个 Socket 同时监听端口 8000,接受最多 8 个客户端连接

工程结构

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

5.TCP_Server_Multi/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 初始化 + 多 Socket TCP 服务器主循环
    ├── tcp_server_multi_socket/
    │   ├── tcp_server_multi_socket.c  ← multi_tcps_socket() 状态机核心
    │   └── tcp_server_multi_socket.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:主循环运行多 Socket TCP Server

文件:USER/main.c

uint16_t local_port = 8000;

while (1)
{
    multi_tcps_socket(ethernet_buf, local_port);
}

主循环中持续调用 multi_tcps_socket() 处理 TCP 服务器状态机。所有 Socket 共用同一个 ethernet_buf 缓冲区,所有 Socket 监听同一端口 local_port(8000)。

同端口多 Socket 监听

W55MH32 的 8 个 Socket 可以绑定同一端口号(如 8000)同时监听。当客户端连接到达时,TOE 硬件自动将连接分配给一个处于 SOCK_LISTEN 状态的空闲 Socket。这种机制无需软件负载均衡,硬件自动分发连接。

步骤2:multi_tcps_socket() 轮询状态机

multi_tcps_socket() 函数基于 getSn_SR(socket_sn) 返回的 Socket 状态执行对应操作。关键在于函数末尾通过静态变量 socket_sn 自增,每次调用处理一个 Socket,下一轮处理下一个 Socket,8 个 Socket 轮询切换。

文件:USER/tcp_server_multi_socket/tcp_server_multi_socket.c | 函数:multi_tcps_socket()

uint8_t socket_sn = 0, socket_flag = 0;

int32_t multi_tcps_socket(uint8_t *buf, uint16_t localport)
{
    int32_t  ret;
    uint16_t size = 0, sentsize = 0;

    switch (getSn_SR(socket_sn))
    {
    case SOCK_ESTABLISHED:                          // 连接已建立
        if (getSn_IR(socket_sn) & Sn_IR_CON)        // 连接成功中断
        {
            setSn_IR(socket_sn, Sn_IR_CON);         // 清除中断标志
        }
        if ((size = getSn_RX_RSR(socket_sn)) > 0)   // 有数据到达
        {
            if (size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
            ret = recv(socket_sn, buf, size);        // 接收数据
            if (ret <= 0) return ret;
            size      = (uint16_t)ret;
            sentsize  = 0;
            buf[size] = 0x00;
            // 回环发送
            while (size != sentsize)
            {
                ret = send(socket_sn, buf + sentsize, size - sentsize);
                if (ret < 0) { close(socket_sn); return ret; }
                sentsize += ret;
            }
        }
        break;
    case SOCK_CLOSE_WAIT:                           // 客户端主动断开
        disconnect(socket_sn);
        break;
    case SOCK_INIT:                                 // Socket已打开
        listen(socket_sn);                          // 进入监听状态
        break;
    case SOCK_CLOSED:                               // Socket未打开
        socket(socket_sn, Sn_MR_TCP, localport, 0x00);  // 打开TCP Socket,绑定端口
        break;
    default:
        break;
    }

    /* 关键:处理完当前 Socket 后切换到下一个 */
    if (socket_sn < _WIZCHIP_SOCK_NUM_)
    {
        socket_sn++;
    }
    else
    {
        socket_sn = 0;
    }
    return 1;
}

轮询切换机制:函数末尾的 socket_sn++ 是核心。每次主循环调用该函数,只处理一个 Socket 的状态机,然后 socket_sn 自增,下次调用处理下一个。当 socket_sn 超过 8 时回绕到 0,实现 8 个 Socket 的循环轮询。

共享缓冲区说明

所有 Socket 共用同一个 ethernet_buf。因为同一时刻只有一个 Socket 在被处理(当前 socket_sn 对应的 Socket),用完缓冲区就切换到下一个,不会发生冲突。相比每 Socket 独立缓存,共享缓存节省内存。

如果你想自定义

  • 改监听端口 → 修改 main.c 中 local_port 的值
  • 减少 Socket 数量 → 修改 socket_sn 回绕的上限(如改为 4,只用 Socket 0-3)
  • 不同端口监听 → 为每个 Socket 准备不同的端口数组,用 ports[socket_sn] 替代 localport

运行验证

打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),观察开发板串口输出。8 个 Socket 会依次打开、监听 8000 端口:

W55MH32 TCP Server Multi Socket 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
1:TCP server loopback start
1:Socket opened
2:TCP server loopback start
2:Socket opened
3:TCP server loopback start
3:Socket opened
4:TCP server loopback start
4:Socket opened
5:TCP server loopback start
5:Socket opened
6:TCP server loopback start
6:Socket opened
7:TCP server loopback start
7:Socket opened
0:Listen, TCP server loopback, port [8000]
1:Listen, TCP server loopback, port [8000]
2:Listen, TCP server loopback, port [8000]
3:Listen, TCP server loopback, port [8000]
4:Listen, TCP server loopback, port [8000]
5:Listen, TCP server loopback, port [8000]
6:Listen, TCP server loopback, port [8000]
7:Listen, TCP server loopback, port [8000]

然后打开 SocketTester,设置为 TCP Client 模式,输入 W55MH32 的 IP 地址和端口号(8000),点击"Connect"连接服务器。可同时建立多个连接(最多 8 个),向每个连接发送数据进行回环测试。

W55MH32 串口输出 — 8 个 Socket 依次打开并监听端口 8000
SocketTester TCP 客户端 — 多个连接同时通信与数据回环测试

常见问题

Q: 8个Socket能监听同一端口吗

可以。W55MH32 的 8 个 Socket 可以绑定同一端口号同时监听。当客户端连接到达时,TOE 硬件自动将连接分配给一个处于 SOCK_LISTEN 状态的空闲 Socket,无需软件干预。

Q: 超过8个客户端同时连接怎么办

W55MH32 最多支持 8 个同时活跃的 TCP 连接。第 9 个客户端的连接请求会被排队或拒绝,直到有现有客户端断开释放 Socket 资源。

Q: 客户端断开后Socket如何复用

客户端断开后 Socket 进入 SOCK_CLOSE_WAIT,调用 disconnect() 后回到 SOCK_CLOSED。下一轮主循环中,SOCK_CLOSED 分支重新打开 Socket 并 listen,回到 SOCK_LISTEN 等待新连接,实现 Socket 循环利用。

Q: 如何为不同Socket设置不同端口

准备一个端口数组(如 uint16_t ports[8] = {8000, 8001, ...}),在调用 multi_tcps_socket() 时传入 ports[socket_sn] 而非固定的 local_port。这样每个 Socket 监听不同端口,可实现多端口服务。

Q: 为什么所有 Socket 共用一个 ethernet_buf

因为 multi_tcps_socket() 每次只处理一个 Socket(当前 socket_sn 对应的 Socket),用完缓冲区后就切换到下一个。同一时刻只有一个 Socket 在读写缓冲区,不会冲突。这样设计节省了内存——如果每个 Socket 分配独立缓存,8 个 Socket 需要 8 倍内存。

总结

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

  • 8 路并发:8 个 Socket 同时监听同一端口,最多接受 8 个客户端连接
  • 轮询切换:multi_tcps_socket() 通过 socket_sn 自增轮流处理每个 Socket,主循环持续调用即可
  • 共享缓冲:所有 Socket 共用 ethernet_buf,节省内存
  • Socket 循环利用:客户端断开后 Socket 重新打开并 listen,持续服务新客户端
  • 灵活扩展:可监听不同端口、减少 Socket 数量,满足不同场景

下载本章例程

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

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

Andy

W5500 技术支持专家