全部例程

W6300多个socket作为TCP服务器

W6300

更新于 2026年10月19日

本篇总结

使用 W6300 的 8 个硬件 Socket 同时作为 TCP 服务器,监听同一端口接受多个客户端连接,实现最多 8 路并发。

🔑 MH2457 + QSPI、UART 调试、硬件 TOE 引擎、TCP、多 Socket、DHCP

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

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W6300-EVB-M4 开发板

本示例演示使用 W6300 的 8 个硬件 Socket 同时作为 TCP 服务器,监听同一端口(5000)接受多个客户端连接进行数据回环测试。核心是在主循环中轮询调用 multi_tcps_socket() 处理所有 8 个 Socket,每个 Socket 独立维护 SOCK_CLOSED → SOCK_INIT → SOCK_LISTEN → SOCK_ESTABLISHED 状态机。

前置工具准备

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

硬件连接与拓扑

┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W6300 │ │ PC │
│8x TCP Srv │ │SocketTester│
│Sock 0-7 │ │TCP Client │
│ IP: DHCP │ │ port:5000 │
│ port:5000 │ │ │
└────┬──────┘ └───────────┘
│ QSPI ↑
┌────┴──────┐ DEBUG USB
│ MH2457 │─────────→ WIZ UartTool
│ MCU │
└───────────┘
网络拓扑:W6300 的 8 个 Socket 同时作为 TCP 服务器监听端口 5000,接受 PC 客户端连接,MH2457 通过 QSPI 驱动 W6300

工程结构

工程核心文件如下:

Project/
├── main.c                    ← 系统入口:串口、GPIO、QSPI 初始化 + user_run()
└── USER/
    ├── user_main.c           ← 网络地址定义 + 多 Socket TCP 服务器主循环 + user_run() 主流程
    ├── tcp_server_multi_socket.c  ← multi_tcps_socket() 状态机核心
    ├── tcp_server_multi_socket.h
    ├── wiz_platform.c/h      ← 平台适配:debug_usart_init、wizchip_gpio_init、hspi_init
    └── wiz_interface.c/h     ← W6300 驱动接口:wizchip_initialize、network_init、PHY 检测、软件定时器

步骤1:主循环运行多 Socket TCP Server 回环测试

文件:USER/user_main.c

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

主循环中调用 multi_tcps_socket(),函数内部通过静态变量 socket_sn 每轮轮询一个 Socket,8 轮覆盖全部 8 个 Socket。所有 Socket 监听同一端口 local_port(5000)。这里 local_port 在 user_main.c 中定义为 5000。

同端口多 Socket 监听

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

步骤2:多 Socket TCP Server 状态机

multi_tcps_socket() 函数基于 getSn_SR(socket_sn) 返回的 Socket 状态执行对应操作,每调用一次处理一个 Socket,然后递增 socket_sn。

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

switch (getSn_SR(socket_sn))
{
case SOCK_ESTABLISHED:
   if (getSn_IR(socket_sn) & Sn_IR_CON)
   {
      getSn_DIPR(socket_sn, destip);
      destport = getSn_DPORT(socket_sn);
      printf("%d:Connected - %d.%d.%d.%d : %d\r\n", socket_sn, destip[0], destip[1], destip[2], destip[3], destport);

      // We need to send a packet of data to activate keepalive
      ret = send(socket_sn, (uint8_t *)"", 1);
      if (ret < 0)
      {
         close(socket_sn);
         return ret;
      }
      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;
      getSn_DIPR(socket_sn, destip);
      destport = getSn_DPORT(socket_sn);
      print_recv_log_ipv4(destip, destport, buf, (uint16_t)ret);
      size = (uint16_t)ret;
      sentsize = 0;
      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:
   printf("%d:CloseWait\r\n", socket_sn);
   if ((ret = disconnect(socket_sn)) != SOCK_OK)
      return ret;
   printf("%d:Socket Closed\r\n", socket_sn);
   break;
case SOCK_INIT:
   printf("%d:Listen, TCP server loopback, port [%d]\r\n", socket_sn, localport);
   if ((ret = listen(socket_sn)) != SOCK_OK)
      return ret;
   break;
case SOCK_CLOSED:
   printf("%d:TCP server loopback start\r\n", socket_sn);
   if ((ret = socket(socket_sn, Sn_MR_TCP4, localport, SOCK_IO_NONBLOCK)) != socket_sn)
      return ret;
   printf("%d:Socket opened\r\n", socket_sn);
   break;
default:
   break;
}

if (socket_sn < (SOCKET_NUMBER - 1U))
{
   socket_sn++;
}
else
{
   socket_sn = 0;
}
return 1;

状态机每轮处理一个 Socket:SOCK_CLOSED 时打开 Socket 并绑定端口,SOCK_INIT 时进入监听,SOCK_ESTABLISHED 时收发数据,SOCK_CLOSE_WAIT 时断开并回到关闭状态。客户端断开后 Socket 回到 SOCK_CLOSED,重新打开并 listen 等待新连接,实现 Socket 资源循环利用。

Socket 资源循环利用

多 Socket 服务器的关键优势是 Socket 资源循环利用。当客户端断开后,该 Socket 回到 SOCK_CLOSED 状态,下一轮循环重新打开并 listen,可接受新的客户端连接。配合 Keepalive 机制清理异常断开的连接,8 个 Socket 可持续服务大量客户端(同一时刻最多 8 个活跃连接)。

如果你想自定义

  • 改监听端口 → 修改 user_main.c 中 local_port 的值
  • 不同端口监听 → 为每个 Socket 准备不同的端口数组,实现多端口服务
  • 减少 Socket 数量 → 修改轮询上限(如只用 4 个 Socket),剩余缓存分配给活跃 Socket 增大吞吐

运行验证

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

MH2457 W6300 QSPI example start
W6300 TCP Server Multi socket example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex

DHCP running
DHCP success!
====================================================================================================
 W6300 network configuration : DHCP

 MAC         : 00:08:DC:12:34:56
 IP          : 192.168.1.8
 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 [5000]
1:Listen, TCP server loopback, port [5000]
2:Listen, TCP server loopback, port [5000]
3:Listen, TCP server loopback, port [5000]
4:Listen, TCP server loopback, port [5000]
5:Listen, TCP server loopback, port [5000]
6:Listen, TCP server loopback, port [5000]
7:Listen, TCP server loopback, port [5000]

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

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

常见问题

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

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

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

W6300 最多支持 8 个同时活跃的 TCP 连接。第 9 个客户端的连接请求会被排队或拒绝,直到有现有客户端断开释放 Socket 资源。Keepalive 机制可加速清理异常断开的连接,提高 Socket 利用率。

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

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

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

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

Q: DATA_BUF_SIZE 最大能设多少

8 个 Socket 均分 64KB 片上 SRAM 时,每 Socket 4KB TX + 4KB RX,DATA_BUF_SIZE 不能超过 4096。若减少 Socket 数量(如只用 2 个),可通过 Sn_TXBUF_SIZE/Sn_RXBUF_SIZE 重新分配,DATA_BUF_SIZE 可增大到 16KB 或更多。

总结

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

  • 8 路并发:8 个 Socket 同时监听同一端口,最多接受 8 个客户端连接
  • 同端口监听:TOE 硬件自动将连接分配给空闲 Socket,无需软件负载均衡
  • Socket 循环利用:客户端断开后 Socket 重新打开并 listen,持续服务新客户端
  • Keepalive 清理:检测异常断开的连接,释放 Socket 资源提高利用率
  • 灵活扩展:可监听不同端口、减少 Socket 数量换取更大缓存,满足不同场景

下载本章例程

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

开发环境: Keil MDK5

Andy

W5500 技术支持专家