全部例程

W6300多个socket作为TCP客户端

W6300

更新于 2026年10月19日

本篇总结

使用 W6300 的 8 个硬件 Socket 同时作为 TCP 客户端,连接同一服务器进行数据回环测试。

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

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

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

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

前置工具准备

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

TCP 协议与多 Socket

W6300 的 TOE 引擎提供 8 个独立硬件 Socket,每个 Socket 可以独立配置为 TCP 客户端、TCP 服务器或 UDP 模式。多 Socket TCP 客户端模式下,8 个 Socket 同时连接同一服务器(或不同服务器),每个 Socket 独立维护连接状态和数据收发。

  • 8 个独立 Socket:Socket 0-7,各自独立运行状态机
  • 轮询切换:主循环调用 multi_tcpc_socket(),函数内通过 socket_sn 自增轮流处理每个 Socket
  • 共享缓冲:所有 Socket 共用一个 ethernet_buf,因为同一时刻只有一个 Socket 在处理
  • 独立端口:每个 Socket 使用不同源端口(50000 起递增)连接服务器

多 Socket 的优势

多 Socket 模式可同时维护多条 TCP 连接,适用于多客户端并发通信场景。例如物联网网关同时连接多个服务器上报数据,或同时与多个设备建立连接。W6300 硬件协议栈自动处理每条连接的 TCP 状态,CPU 只需轮询处理,无需软件多路复用。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W6300 处于同一网段。PC 端需运行 TCP 服务器程序,可接受 8 个客户端连接。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
  3. 确保 W6300 与 MH2457 之间的 QSPI 连线正确(CSn、SCK、DATA0~DATA3)
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W6300 │ │ PC │
│8x TCP Clt │ │SocketTester│
│Sock 0-7 │ │TCP Server │
│ IP: DHCP │ │ port:5000 │
└────┬──────┘ └───────────┘
│ QSPI ↑
┌────┴──────┐ DEBUG USB
│ MH2457 │─────→ WIZ UartTool
│ MCU │
└───────────┘
网络拓扑:W6300 的 8 个 Socket 同时作为 TCP 客户端连接 PC 服务器,MH2457 通过 QSPI 驱动 W6300

工程结构

工程核心文件如下:

Project/
├── main.c                    ← 系统入口:串口、GPIO、QSPI 初始化 + user_run()
└── USER/
    ├── user_main.c           ← 网络地址定义 + 目标服务器 + user_run() 主流程
    ├── tcp_client_multi_socket.c  ← multi_tcpc_socket() 状态机核心
    ├── tcp_client_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 Client

文件:USER/user_main.c

uint8_t  dest_ip[4]   = {192, 168, 1, 20};
uint16_t dest_port    = 5000U;

while (1)
{
    multi_tcpc_socket(ethernet_buf, dest_ip, dest_port);
}

主循环中持续调用 multi_tcpc_socket() 处理 TCP 客户端状态机。所有 Socket 共用同一个 ethernet_buf 缓冲区,连接同一服务器(192.168.1.20:5000)。

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

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

文件:USER/tcp_client_multi_socket.c | 函数:multi_tcpc_socket()

uint8_t  socket_sn = 0, socket_flag = 0;
uint16_t any_port  = 50000;

int32_t multi_tcpc_socket(uint8_t *buf, uint8_t *destip, uint16_t destport)
{
    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)
        {
            ret = send(socket_sn, (uint8_t *)"", 1);   // 激活 keepalive
            if (ret < 0) { close(socket_sn); return ret; }
            printf("%d:Connected to - %d.%d.%d.%d : %d\r\n",
                   socket_sn, destip[0], destip[1], destip[2], destip[3], destport);
            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;
            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:Try to connect to the %d.%d.%d.%d : %d\r\n",
               socket_sn, destip[0], destip[1], destip[2], destip[3], destport);
        if ((ret = connect(socket_sn, destip, destport, 4)) != SOCK_OK)
            return ret;
        break;

    case SOCK_CLOSED:
        close(socket_sn);
        if ((ret = socket(socket_sn, Sn_MR_TCP4, any_port++, SOCK_IO_NONBLOCK)) != socket_sn)
        {
            if (any_port == 0xffff) any_port = 50000;
            return ret;
        }
        printf("%d:TCP client loopback start\r\n", socket_sn);
        printf("%d:Socket opened\r\n", socket_sn);
        break;

    default:
        break;
    }

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

轮询切换机制:函数末尾的 socket_sn++ 是核心。每次主循环调用该函数,只处理一个 Socket 的状态机,然后 socket_sn 自增,下次调用处理下一个。当 socket_sn 达到 7 时回绕到 0,实现 8 个 Socket 的循环轮询。W6300 的 socket() 使用 Sn_MR_TCP4 和 SOCK_IO_NONBLOCK,connect() 需要传入地址长度 4(IPv4)。

共享缓冲区说明

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

如果你想自定义

  • 改目标 IP/端口 → 修改 user_main.c 中 dest_ip 和 dest_port
  • 减少 Socket 数量 → 修改 socket_sn 回绕的上限(如改为 4,只用 Socket 0-3)
  • 连接不同服务器 → 为每个 Socket 准备不同的 dest_ip 和 dest_port 数组,用 dest_ip[socket_sn] 替代

运行验证

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

MH2457 W6300 QSPI example start
W6300 TCP Client 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 client loopback start
0:Socket opened
1:TCP client loopback start
1:Socket opened
2:TCP client loopback start
2:Socket opened
3:TCP client loopback start
3:Socket opened
4:TCP client loopback start
4:Socket opened
5:TCP client loopback start
5:Socket opened
6:TCP client loopback start
6:Socket opened
7:TCP client loopback start
7:Socket opened
0:Try to connect to the 192.168.1.20 : 5000
0:Try to connect to the 192.168.1.20 : 5000
0:Connected to - 192.168.1.20 : 5000
1:Try to connect to the 192.168.1.20 : 5000
1:Try to connect to the 192.168.1.20 : 5000
1:Connected to - 192.168.1.20 : 5000
2:Try to connect to the 192.168.1.20 : 5000
2:Try to connect to the 192.168.1.20 : 5000
2:Connected to - 192.168.1.20 : 5000
3:Try to connect to the 192.168.1.20 : 5000
3:Try to connect to the 192.168.1.20 : 5000
3:Connected to - 192.168.1.20 : 5000
4:Try to connect to the 192.168.1.20 : 5000
4:Try to connect to the 192.168.1.20 : 5000
4:Connected to - 192.168.1.20 : 5000
5:Try to connect to the 192.168.1.20 : 5000
5:Try to connect to the 192.168.1.20 : 5000
5:Connected to - 192.168.1.20 : 5000
6:Try to connect to the 192.168.1.20 : 5000
6:Try to connect to the 192.168.1.20 : 5000
6:Connected to - 192.168.1.20 : 5000
7:Try to connect to the 192.168.1.20 : 5000
7:Try to connect to the 192.168.1.20 : 5000
7:Connected to - 192.168.1.20 : 5000

然后打开 SocketTester,设置为 TCP Server 模式,选择 PC 的 IP 地址和端口号(5000),点击"Listen"开始侦听。W6300 的 8 个 Socket 会依次连接服务器,连接成功后可向每个连接发送数据进行回环测试。

WIZ UartTool 串口输出 — 8 个 Socket 依次打开并连接服务器
SocketTester TCP 服务器 — 8 个客户端连接与数据回环测试

常见问题

Q: 8个Socket能连接同一服务器吗

可以。W6300 的 8 个 Socket 可以分别作为 TCP 客户端,同时连接同一服务器的同一端口。服务器会看到 8 条独立的 TCP 连接,每条连接使用不同的客户端源端口(从 50000 起递增)。

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

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

Q: 8个Socket能连接不同的服务器吗

可以。只需为每个 Socket 准备不同的目标 IP 和端口数组,在调用 multi_tcpc_socket() 时传入对应的参数即可。本例为简化演示,8 个 Socket 连接同一服务器。

Q: 为什么有些Socket连接失败

可能原因:1) 服务器并发连接数限制;2) 端口冲突(any_port 溢出);3) 网络拥塞导致超时。检查服务器最大连接数设置,确保支持 8 个并发连接。

Q: 轮询8个Socket会影响性能吗

影响极小。TOE 硬件自动维护 TCP 协议栈,CPU 只需读取 Sn_SR 状态寄存器并执行对应操作。8 次 getSn_SR() 读取加状态处理的总耗时在微秒级,不会成为性能瓶颈。

总结

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

  • 8 个独立 Socket:W6300 TOE 支持 8 个硬件 Socket,每个独立运行状态机
  • 轮询切换:multi_tcpc_socket() 通过 socket_sn 自增轮流处理每个 Socket,主循环持续调用即可
  • 共享缓冲:所有 Socket 共用 ethernet_buf,节省内存
  • 独立源端口:每个 Socket 使用不同源端口(any_port 从 50000 起递增),服务器可区分不同连接
  • W6300 平台特有:socket() 使用 Sn_MR_TCP4 和 SOCK_IO_NONBLOCK,connect() 需要传入地址长度 4(IPv4)
  • 灵活扩展:可连接不同服务器、减少 Socket 数量,满足不同应用场景

下载本章例程

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

开发环境: Keil MDK5

Andy

W5500 技术支持专家