全部例程

W6300作为 IPv6 TCP客户端与服务器

W6300

更新于 2026年10月15日

本篇总结

使用 W6300 的硬件 TOE 引擎在 IPv6 双协议栈下同时运行 TCP 服务器和 TCP 客户端,先通过无状态地址自动配置(SLAAC)获取 IPv6 地址,再进行数据回环测试。

🔑 MH2457、QSPI、UART 调试、硬件 TOE 引擎、IPv6、SLAAC、TCP

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

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

本示例演示使用 W6300 的硬件 TOE 引擎在 IPv6 环境下同时运行 TCP 服务器和 TCP 客户端。W6300 原生支持 IPv4/IPv6 双协议栈,本例程先通过 DAD 检测生成 Link-local 地址,再通过路由器公告(RA)进行无状态地址自动配置(SLAAC)获取 Global 地址,最后在主循环中并行运行 TCP 服务器(监听 5000)和 TCP 客户端(连接指定 IPv6 地址)。

前置工具准备

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

IPv6 TCP 通信简介

IPv6 是下一代互联网协议,相比 IPv4 具有更大的地址空间、更简化的报文头和更好的安全性。W6300 片内集成完整的硬件双协议栈 TCP/IP,支持 IPv4、IPv6 以及双栈模式,Socket 可通过 Sn_MR_TCP4、Sn_MR_TCP6、Sn_MR_TCPD 选择协议栈模式。

IPv6 地址获取通常分两步:

  • Link-local 地址:设备根据 MAC 地址自动生成 Link-local 地址(FE80::/10 前缀),并通过 DAD(重复地址检测)确认该地址在链路上唯一。
  • Global 地址:通过路由器公告(RA)进行无状态地址自动配置(SLAAC),或通过 DHCPv6 向服务器申请。

SLAAC 无状态地址自动配置

SLAAC(Stateless Address Autoconfiguration)是 IPv6 中通过路由器公告(RA)自动配置地址的机制。路由器周期性发送 RA 报文,包含网络前缀、网关、DNS 等信息。设备根据 RA 中的前缀和自身的接口标识符组合生成 Global 地址。本例程通过 W6300 的 MACRAW 模式捕获 RA 报文并解析,完成地址自动配置。

硬件连接与拓扑

请注意:

测试需要路由器支持并开启 IPv6,且发送 RA 公告。PC 和开发板需在同一网段。PC 端作为 TCP 客户端/服务器与开发板通信。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌─────────────────────────────────┐
│ 路由器(IPv6 RA / DHCPv6) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W6300 │ │ PC │
│ TCP Srv │ │SocketTester│
│ TCP Clt │ │TCP Clt/Srv│
│ IPv6 SLAAC│ │ IPv6 │
└────┬──────┘ └───────────┘
│ QSPI ↑
┌────┴──────┐ DEBUG USB
│ MH2457 │─────────→ WIZ UartTool
│ MCU │
└───────────┘
网络拓扑:MH2457 通过 QSPI 驱动 W6300,W6300 在 IPv6 环境下同时运行 TCP 服务器(5000)和 TCP 客户端

工程结构

工程核心文件如下:

Project/
├── main.c                    ← 系统入口:串口、GPIO、QSPI 初始化 + user_run()
└── USER/
    ├── user_main.c           ← IPv6 自动配置 + TCP 服务器/客户端主循环
    ├── ipv6_aac.c/h          ← IPv6 无状态地址自动配置(SLAAC)
    ├── ipv6_common.c/h       ← IPv6 地址准备与打印
    ├── loopback_compat.c/h   ← IPv6 TCP 服务器/客户端封装(重连退避)
    ├── loopback.c/h          ← loopback_tcps() / loopback_tcpc() 状态机核心
    ├── wiz_platform.c/h      ← 平台适配:debug_usart_init、wizchip_gpio_init、hspi_init
    └── wiz_interface.c/h     ← W6300 驱动接口:wizchip_initialize、network_init、PHY 检测、软件定时器

步骤1:IPv6 地址自动配置

文件:USER/ipv6_aac.c — 先通过 ipv6_prepare_network() 初始化网络参数,再调用 AddressAutoConfig_Init() 执行 DAD 检测和 RA 解析,获取 Link-local 和 Global 地址。

if (ipv6_prepare_network(&net_info, mac, NETINFO_SLAAC_V6, NETINFO_STATIC) < 0)
{
    return -1;
}

/* AddressAutoConfig may enter DHCPv6 paths depending on RA M/O flags. */
wiz_add_timer(DHCP6_time_handler, 1000U);
result = AddressAutoConfig_Init(IPV6_AAC_SOCKET, &net_info);
wiz_delete_timer(DHCP6_time_handler);

if (result != 1U)
{
    return -1;
}

wizchip_getnetinfo(&net_info);
if (ipv6_address_is_zero(net_info.lla) || ipv6_address_is_zero(net_info.gua))
{
    return -1;
}

ipv6_print_address("Link-local address: ", net_info.lla);
ipv6_print_address("Global address: ", net_info.gua);
if (!ipv6_address_is_zero(net_info.gw6))
{
    ipv6_print_address("IPv6 gateway: ", net_info.gw6);
}
if (!ipv6_address_is_zero(net_info.dns6))
{
    ipv6_print_address("IPv6 DNS: ", net_info.dns6);
}

软件定时器

W6300 的 DHCPv6 时基通过 wiz_add_timer(DHCP6_time_handler, 1000) 注册到软件定时器链表,由 1ms 中断调用 wiz_timer_handler() 驱动。地址自动配置完成后调用 wiz_delete_timer() 删除定时器。

步骤2:主循环并行运行 TCP 服务器与客户端

文件:USER/user_main.c — 先设置两个 Socket 的 Keepalive,然后在主循环中并行调用 ipv6_tcp_server_run() 和 ipv6_tcp_client_run()。

/* Match the W5500 TCP Client/Server keepalive placement. */
setSn_KPALVTR(TCP_SERVER_SOCKET_ID, 6U);
setSn_KPALVTR(TCP_CLIENT_SOCKET_ID, 6U);

while (1)
{
    (void)ipv6_tcp_server_run(TCP_SERVER_SOCKET_ID, ethernet_buf, tcp_server_port);
    (void)ipv6_tcp_client_run(TCP_CLIENT_SOCKET_ID, ethernet_buf, tcp_client_dest_ip6, tcp_client_dest_port);
}

KeepAlive 的时间单元为 5 秒,设置 6 个单元即每 30 秒发送一次 KeepAlive 报文,用于检测长时间空闲的连接是否仍然有效。TCP 服务器和客户端分别使用不同的 Socket,在主循环中交替运行,互不干扰。

static const uint8_t app_mac[6] = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56};
static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};
static uint8_t tcp_client_dest_ip6[16] = {
    0x24, 0x0e, 0x03, 0x3d, 0x94, 0x5a, 0xa3, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6b
};
static const uint16_t tcp_server_port = 5000U;
static const uint16_t tcp_client_dest_port = 5001U;

步骤3:TCP 服务器/客户端状态机

文件:USER/loopback_compat.c — ipv6_tcp_server_run() 和 ipv6_tcp_client_run() 设置 IPv6 模式后调用底层 loopback_tcps() / loopback_tcpc() 状态机。

int32_t ipv6_tcp_server_run(uint8_t sn, uint8_t *buf, uint16_t port)
{
    if (set_loopback_mode_W6x00(AS_IPV6) != 0)
    {
        return -1;
    }
    return loopback_tcps(sn, buf, port);
}

int32_t ipv6_tcp_client_run(uint8_t sn, uint8_t *buf, uint8_t *dest_ip6, uint16_t dest_port)
{
    int32_t ret;

    if (sn >= _WIZCHIP_SOCK_NUM_)
    {
        return SOCKERR_SOCKNUM;
    }

    if (!tcp_client_retry_ready(sn))
    {
        return SOCK_BUSY;
    }

    if (set_loopback_mode_W6x00(AS_IPV6) != 0)
    {
        tcp_client_schedule_retry(sn);
        return -1;
    }

    ret = loopback_tcpc(sn, buf, dest_ip6, dest_port);

    if ((ret < 0) && (ret != SOCK_BUSY))
    {
        tcp_client_schedule_retry(sn);
    }

    return ret;
}

重连退避机制

TCP 客户端连接失败时,tcp_client_schedule_retry() 记录下次重试时间,tcp_client_retry_ready() 在重试时间到达前返回 SOCK_BUSY,避免主循环被连接阻塞,也避免过于频繁地重试打印。TCP 服务器和其余应用逻辑在此期间继续运行。

运行验证

打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1)。烧录例程运行后,首先进行 PHY 链路检测,然后执行 DAD 检测和 RA 解析,完成 IPv6 地址自动配置后启动 TCP 服务器和客户端。预期串口输出如下:

MH2457 W6300 QSPI example start
W6300 IPv6 TCP Client / Server example
PHY no link
PHY no link
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
Duplicate_Address_Detection
Wait RQIR.....

Timeout !!! DAD SUCCESSED

flags = 0x80
Address_Auto_Configuration Start
RA capture mode : W6300 MACRAW
Sn_SR : 42
RA
type : 86
code : 0
RA_flag : c0
Router_lifetime : 1800 s
Reachable_time : 0 ms
Retrans_time : 0 ms
Option Type : 1, length : 8
Option Type : 5, length : 8

Option Type : 3, length : 32
Prefix Length : 64
Prefix Information Flag : c0
valid lifetime : 238095
preferred lifetime : 151695
Accepted first autonomous /64 PIO
Option Type : 25, length : 24
DNS lifetime : 1800
Option Type : 7, length : 8
MO normalized result : 3
RA requests Stateful DHCPv6
Mac address : 00:08:dc:12:34:56
your Link Local IP is fe80:0000:0000:0000:0208:dcff:fe12:3456
your Global IP is 240e:033d:945a:a301:0208:dcff:fe12:3456

your Gateway IP is fe80:0000:0000:0000:0000:0000:0000:0002
your DNSv6 is 240e:033d:945a:a301:0000:0000:0000:0001
Stateful DHCPv6 succeeded
Link-local address: FE80:0000:0000:0000:0208:DCFF:FE12:3456
Global address: 240E:033D:945A:A301:0000:0000:0000:05EC
IPv6 gateway: FE80:0000:0000:0000:0000:0000:0000:0002
IPv6 DNS: 240E:033D:945A:A301:0000:0000:0000:0001
IPv6 auto configuration complete; starting application loop
1:TCP server loopback start
1:Socket opened[19]
1:Listen, TCP server loopback, port [5000] as IPv6 mode

串口输出依次显示 DAD 检测成功、RA 报文解析(包含前缀、DNS、网关等选项)、IPv6 地址自动配置完成,最后 TCP 服务器在 IPv6 模式下监听 5000 端口。主循环中 TCP 客户端也会同时运行,主动连接代码中指定的 IPv6 服务器地址。

WIZ UartTool 串口输出— W6300 作为 TCP 服务器,PC 以 IPv6 连接 5000 端口进行数据回环
WIZ UartTool 串口输出 — W6300 作为 TCP 客户端,主动连接 PC 的 IPv6 服务器进行数据回环

常见问题

Q: 为什么 IPv6 要先做 DAD 检测

IPv6 设备在链路上通信前必须先拥有一个唯一的 Link-local 地址。DAD(重复地址检测)通过发送邻居请求确认该地址没有被其他设备占用,确保地址唯一后才能继续获取 Global 地址。串口打印 "DAD SUCCESSED" 表示地址可用。

Q: SLAAC 和 DHCPv6 有什么区别

SLAAC(无状态地址自动配置)通过路由器发送的 RA 报文自动生成地址,无需服务器分配,路由器不维护地址状态;DHCPv6(有状态)由 DHCPv6 服务器统一分配地址并维护租约。本例程通过 RA 的 M/O 标志判断使用哪种方式,RA 要求有状态 DHCPv6 时会进入 DHCPv6 流程。

Q: 为什么 TCP 客户端连接失败后要退避重试

TCP 客户端在服务器未开启时会反复连接失败。如果每次失败都立即重试,会在主循环中产生大量重试和串口打印。通过 tcp_client_schedule_retry() 记录下次重试时间,在重试时间到达前返回 SOCK_BUSY,既能继续轮询连接进度,又不会阻塞主循环。

Q: IPv6 TCP 服务器和客户端可以同时运行吗

可以。W6300 的 TOE 引擎支持 8 个独立 Socket,服务器和客户端使用不同的 Socket,在主循环中交替调用各自的运行函数即可并行工作。服务器 Socket 监听固定端口,客户端 Socket 主动连接远端服务器,两者互不干扰。

Q: IPv6 地址自动配置失败怎么办

排查步骤:1) 确认路由器支持并开启 IPv6,且发送 RA 公告;2) 确认 PC 和 W6300 在同一网段;3) 检查串口是否打印 DAD SUCCESSED 和 RA 解析信息;4) 若 RA 未收到,检查路由器 IPv6 配置;5) 程序在自动配置失败时不会启动应用循环,可根据串口提示定位问题。

总结

本文基于 W6300 硬件 TCP/IP 协议栈实现了 IPv6 环境下的 TCP 服务器与客户端并行通信:

  • 地址获取:先通过 DAD 生成 Link-local 地址,再通过 RA 解析完成 SLAAC 无状态地址自动配置,必要时进入 DHCPv6
  • 双栈支持:W6300 支持 IPv4/IPv6/双栈模式,通过 socket() 的 Sn_MR_TCP4/TCP6/TCPD 选择
  • 并行运行:TCP 服务器和客户端使用不同 Socket,主循环中交替调用,互不干扰
  • 重连退避:客户端连接失败后按时间间隔退避重试,避免阻塞主循环和频繁打印
  • Keepalive:通过 setSn_KPALVTR 设置保活时间(5 秒/单元),检测空闲连接有效性

下载本章例程

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

开发环境: Keil MDK5

Andy

W5500 技术支持专家