本篇总结
使用 W6300 的硬件 TOE 引擎实现 TCP 客户端模式,连接服务器进行数据回环测试,支持 IPv4/IPv6 双协议栈与 Keepalive 保活机制。
🔑 MH2457、QSPI、UART调试、硬件TOE引擎、TCP、DHCP
硬件平台 :本例程基于 W6300-EVB-M4 开发板运行。
采购推荐 :点击前往 WIZnet 官方淘宝店铺 选购 W6300-EVB-M4 开发板
本示例演示使用 W6300 的硬件 TOE 引擎实现 TCP 客户端模式,主动连接服务器进行数据回环测试。核心是基于 Socket 状态机的 loopback_tcpc() 函数,在 SOCK_CLOSED → SOCK_INIT → SOCK_ESTABLISHED 状态间切换,实现连接、收发、断开全流程,并支持 Keepalive 保活机制。W6300 支持 IPv4/IPv6 双协议栈,Socket 可配置为 TCP4、TCP6 或双栈模式。
前置工具准备
开始本例程前,请确认以下工具已安装:
WIZ UartTool V1.0 :串口调试工具:点击下载
SocketTester :网络调试工具:点击下载
TCP 协议简介
TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议,用于在网络中可靠地传输数据。TCP 是互联网协议族中的核心协议之一,通常与 IP 协议一起使用,形成套接字通信。TCP 通过三次握手建立连接、四次挥手断开连接,提供可靠性(超时重传、快速重传)、流量控制(滑动窗口)和拥塞控制等机制。
面向连接: 传输数据前通过三次握手建立连接
可靠性: 数据丢失或出错时自动重传
流量控制: 滑动窗口机制调节发送速度
全双工通信: 两个方向同时传输数据
Keepalive: Sn_KPALVTR 寄存器,5秒为单位,检测空闲连接是否有效
W6300 的 TCP 优势
W6300 片内集成了完整的硬件双协议栈 TCP/IP,TCP 的三次握手、数据确认、重传、滑动窗口等机制全部在 TOE 硬件内部完成。MCU 只需通过 QSPI 读写 Socket 寄存器,调用 connect()/send()/recv() 等 API 即可实现 TCP 通信,无需在软件中实现 TCP 协议栈。W6300 还支持 IPv4 / IPv6 双栈通信,Socket 可根据需求配置为 TCP4、TCP6 或双栈模式。
硬件连接与拓扑
请注意:
测试需要 PC 端和 W6300 处于同一网段。PC 端需运行 TCP 服务器程序。
Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
网线连接开发板 RJ45 网口 到路由器 LAN 口
确保 W6300 与 MH2457 之间的 QSPI 连线正确(CSn、SCK、DATA0~DATA3)
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W6300 │ │ PC │
│TCP Client │ │SocketTester│
│ IP: DHCP │ │TCP Server │
└────┬──────┘ └───────────┘
│ QSPI ↑
┌────┴──────┐ DEBUG USB
│ MH2457 │──────────→ WIZ UartTool
│ MCU │
└───────────┘
网络拓扑:W6300 作为 TCP 客户端主动连接 PC 上的 TCP 服务器,MH2457 通过 QSPI 驱动 W6300
工程结构
文件:USER/user_main.c
/* 30 s keepalive; unit is 5 seconds. */
setSn_KPALVTR(SOCKET_ID, 6);
在 W6300 中,KeepAlive 的时间单元同样为 5 秒,设置 6 个单元则每 30 秒发送一次 KeepAlive 报文。Keepalive 用于检测长时间空闲的连接是否仍然有效,避免假连接。
步骤1:开启TCP Keepalive功能
文件:USER/user_main.c
/* 30 s keepalive; unit is 5 seconds. */
setSn_KPALVTR(SOCKET_ID, 6);
在 W6300 中,KeepAlive 的时间单元同样为 5 秒,设置 6 个单元则每 30 秒发送一次 KeepAlive 报文。Keepalive 用于检测长时间空闲的连接是否仍然有效,避免假连接。
步骤2:主循环运行TCP Client回环测试 文件:USER/user_main.c
while (1)
{
loopback_tcpc(SOCKET_ID, ethernet_buf, dest_ip, dest_port);
}
四个传参分别为:SOCKET ID、TCP协议缓存数组、目标服务器IP地址、目标服务器端口号。示例目标地址为 192.168.1.20:5000。主循环不断调用状态机函数,由状态机内部根据 Socket 状态执行对应操作。
步骤3:TCP Client状态机
loopback_tcpc() 函数基于 getsockopt(sn, SO_STATUS, &status) 返回的 Socket 状态执行对应操作:
Socket状态 执行操作
SOCK_CLOSED 配置端口并打开 TCP Socket(按协议栈模式选择 TCP4/TCP6/TCPD),进入 SOCK_INIT
SOCK_INIT 调用 connect() 连接服务器,成功后进入 SOCK_ESTABLISHED;W6300 对非阻塞连接返回 SOCK_BUSY,需等待连接中断或超时
SOCK_ESTABLISHED 清除连接中断,接收数据并回环发送
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)
{
check_loopback_mode_W6x00();
int32_t ret;
uint16_t sentsize = 0;
uint8_t status, inter;
uint16_t received_size;
uint8_t tmp = 0;
uint8_t arg_tmp8;
static uint16_t any_port = 50000;
getsockopt(sn, SO_STATUS, &status);
switch (status)
{
case SOCK_ESTABLISHED:
ctlsocket(sn, CS_GET_INTERRUPT, &inter);
if (inter & Sn_IR_CON)
{
arg_tmp8 = Sn_IR_CON;
ctlsocket(sn, CS_CLR_INTERRUPT, &arg_tmp8);
}
getsockopt(sn, SO_RECVBUF, &received_size);
if (received_size > 0)
{
if (received_size > DATA_BUF_SIZE)
received_size = DATA_BUF_SIZE;
ret = recv(sn, buf, received_size);
if (ret <= 0) return ret;
received_size = (uint16_t)ret;
sentsize = 0;
while (received_size != sentsize)
{
ret = send(sn, buf + sentsize, received_size - sentsize);
if (ret < 0) { close(sn); return ret; }
sentsize += ret;
}
}
break;
case SOCK_CLOSE_WAIT:
getsockopt(sn, SO_RECVBUF, &received_size);
if (received_size > 0)
{
if (received_size > DATA_BUF_SIZE)
received_size = DATA_BUF_SIZE;
ret = recv(sn, buf, received_size);
if (ret <= 0) return ret;
received_size = (uint16_t)ret;
sentsize = 0;
while (received_size != sentsize)
{
ret = send(sn, buf + sentsize, received_size - sentsize);
if (ret < 0) { close(sn); return ret; }
sentsize += ret;
}
}
if ((ret = disconnect(sn)) != SOCK_OK) return ret;
break;
case SOCK_INIT:
if (loopback_mode == AS_IPV4)
ret = connect(sn, destip, destport, 4);
else if (loopback_mode == AS_IPV6)
ret = connect(sn, destip, destport, 16);
if (ret == SOCK_BUSY) return ret;
if (ret != SOCK_OK) return ret;
break;
case SOCK_CLOSED:
switch (loopback_mode)
{
case AS_IPV4: tmp = socket(sn, Sn_MR_TCP4, any_port++, SOCK_IO_NONBLOCK); break;
case AS_IPV6: tmp = socket(sn, Sn_MR_TCP6, any_port++, SOCK_IO_NONBLOCK); break;
case AS_IPDUAL: tmp = socket(sn, Sn_MR_TCPD, any_port++, SOCK_IO_NONBLOCK); break;
default: break;
}
if (tmp != sn) return SOCKERR_SOCKNUM;
break;
default:
break;
}
return 1;
}
状态机核心:SOCK_CLOSED 时打开 Socket(端口自动递增),SOCK_INIT 时 connect() 连接服务器,SOCK_ESTABLISHED 时收发数据,SOCK_CLOSE_WAIT 时断开连接。TOE 硬件自动维护 TCP 协议栈,用户只需轮询 Socket 状态并根据状态做相应处理。
getsockopt(sn, SO_STATUS, ...) — W6300 Socket 状态查询
W6300 ioLibrary 使用 getsockopt(sn, SO_STATUS, &status) 读取 Socket n 的状态,返回值指示该 Socket 当前状态——SOCK_CLOSED、SOCK_INIT、SOCK_ESTABLISHED、SOCK_CLOSE_WAIT 等。W6300 的 Socket API 基于 BSD Socket 风格,读写缓存使用 getsockopt(sn, SO_RECVBUF, ...) 查询,发送/接收分别使用 send() 和 recv()。
端口自动递增
W6300 异常断开时服务器不知道客户端掉线,继续使用上次端口连接会被拒绝。因此连接失败后端口自动加1(从50000开始)。若服务器要求固定端口,则不能使用此机制。
如果你想自定义
改目标服务器地址 → 修改 user_main.c 中 dest_ip 和 dest_port 的值
改用 IPv6 或双栈模式 → 调用 set_loopback_mode_W6x00(AS_IPV6) 或 AS_IPDUAL
提高吞吐量 → 通过 Socket 缓存重新分配大小,同时增大 DATA_BUF_SIZE
改用其他 Socket 编号 → 修改 SOCKET_ID 宏(W6300 支持 0-7 共 8 个 Socket)
运行验证
打开 WIZ UartTool V1.0 ,连接 DEBUG USB 对应 COM 口(115200 / 8N1),观察开发板串口输出。当服务器未开启时,会一直打印打开 Socket 和连接服务器提示消息:
MH2457 W6300 QSPI example start
W6300 TCP Client 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:Opened, TCP Client
0:Connect to 192.168.1.20:5000
然后打开 SocketTester ,设置为 TCP Server 模式,选择 PC 的 IP 地址和端口号(5000),点击"Listen"开始侦听。W6300 连接成功后,向其发送数据即可进行回环测试。
WIZ UartTool 串口输出 — TCP 客户端初始化(PHY 链路 + DHCP + TCP 连接) WIZ UartTool + SocketTester TCP 服务器 — 数据回环测试 常见问题
Q: 为什么W6300连接服务器时端口会自动变化
W6300 异常断开时,服务器端并不知道客户端已掉线,继续使用上次连接的端口会被服务器拒绝。因此连接失败后端口自动加1(从50000开始)。若服务器要求固定端口,需修改代码取消自动递增。
Q: Keepalive 如何配置和激活
通过 setSn_KPALVTR(sn, 6) 设置 Keepalive 时间(6×5秒=30秒)。激活方式:在 socket 成功连接服务器后(SOCK_ESTABLISHED 状态),调用 send() 发送一条数据即可激活 Keepalive 功能。
Q: W6300 支持哪些协议栈模式
W6300 支持 IPv4、IPv6 以及 IPv4/IPv6 双栈三种模式。创建 Socket 时通过 Sn_MR_TCP4、Sn_MR_TCP6、Sn_MR_TCPD 选择。双栈模式下 Socket 可同时处理 IPv4 和 IPv6 连接。可通过 set_loopback_mode_W6x00() 设置当前模式,默认使用 IPv4。
Q: SOCK_CLOSE_WAIT 状态是什么意思
当服务器主动断开连接时,Socket 进入 SOCK_CLOSE_WAIT 半关闭状态,此时仍可进行关闭前最后的数据传输。W6300 在进入该状态后会先接收剩余数据并回发,再调用 disconnect() 断开连接,避免数据丢失。
总结
本文基于 W6300 硬件 TCP/IP 协议栈实现了 TCP 客户端模式通信:
TCP协议: 面向连接、可靠传输,通过三次握手建立连接、四次挥手断开连接
核心函数: loopback_tcpc() 基于 Socket 状态机实现 SOCK_CLOSED→SOCK_INIT→SOCK_ESTABLISHED 全流程
Keepalive: 通过 Sn_KPALVTR 寄存器设置保活时间(5秒/单元),连接后发送数据激活
双协议栈: W6300 支持 IPv4 / IPv6 / 双栈模式,通过 socket() 的 Sn_MR_TCP4/TCP6/TCPD 选择
端口递增: 连接失败时端口自动加1避免被服务器拒绝,固定端口场景需修改代码
吞吐优化: 调整 Socket 缓存和 DATA_BUF_SIZE 提升数据吞吐量