1. 所需的头文件
您需要在代码文件的顶部包含以下三个头文件,才能使用所有相关的底层函数。
#include <esp_netif.h> // 用于访问底层的网络接口 (netif)
#include "lwip/sockets.h" // 用于访问网络套接字函数,如此处的 ntohl()
#include <WiFi.h> // 用于启用WiFi和IPv6功能
2. IPv6 地址格式化与获取函数
这是解决问题的核心。由于标准库函数不可用,我们手动创建了 formatIPv6 函数,然后由 getIPv6 调用它。
/**
* @brief 手动将底层的 esp_ip6_addr_t 结构体格式化为人类可读的字符串。
* @param addr 指向IPv6地址结构体的指针。
* @return 格式化后的IPv6地址字符串。
*/
String formatIPv6(const esp_ip6_addr_t *addr) {
if (addr == nullptr) {
return String("::");
}
char buf[40];
// ESP32是小端序,网络字节序是大端序,需要转换才能正确拼接。
uint32_t word0 = ntohl(addr->addr[0]);
uint32_t word1 = ntohl(addr->addr[1]);
uint32_t word2 = ntohl(addr->addr[2]);
uint32_t word3 = ntohl(addr->addr[3]);
// 使用 snprintf 安全地将4个32位整数格式化为8个16位的十六进制数
snprintf(buf, sizeof(buf), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
(uint16_t)(word0 >> 16),
(uint16_t)(word0 & 0xFFFF),
(uint16_t)(word1 >> 16),
(uint16_t)(word1 & 0xFFFF),
(uint16_t)(word2 >> 16),
(uint16_t)(word2 & 0xFFFF),
(uint16_t)(word3 >> 16),
(uint16_t)(word3 & 0xFFFF)
);
return String(buf);
}
/**
* @brief 获取设备的IPv6地址。
* @return 返回IPv6地址字符串。如果获取失败,则返回 "Not Available"。
*/
String getIPv6() {
// 获取WiFi STA网络接口的句柄
esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
if (!netif) return String("Not Available");
esp_ip6_addr_t addr;
// 优先尝试获取全局IPv6地址 (2000::/3),这是公网可路由的
if (esp_netif_get_ip6_global(netif, &addr) == ESP_OK) {
// 检查地址是否不为全0
if (addr.addr[0] != 0 || addr.addr[1] != 0 || addr.addr[2] != 0 || addr.addr[3] != 0) {
return formatIPv6(&addr); // 使用我们的手动格式化函数
}
}
// 如果没有全局地址,则获取本地链路地址 (fe80::/10),仅在局域网内有效
if (esp_netif_get_ip6_linklocal(netif, &addr) == ESP_OK) {
if (addr.addr[0] != 0 || addr.addr[1] != 0 || addr.addr[2] != 0 || addr.addr[3] != 0) {
return formatIPv6(&addr); // 使用我们的手动格式化函数
}
}
return String("Not Available");
}
3. 在 setup() 函数中的调用示例
在连接WiFi成功后,您需要先启用IPv6,然后就可以调用 getIPv6() 函数了。
void setup() {
// ... 其他初始化代码 ...
// 连接WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi 已连接!");
// 启用IPv6功能
WiFi.enableIPv6();
// 稍微等待一下,让网络协议栈有时间获取到地址
delay(1000);
// 打印IPv4和IPv6地址
Serial.print("IPv4 地址: ");
Serial.println(WiFi.localIP());
Serial.print("IPv6 地址: ");
Serial.println(getIPv6()); // 调用我们的函数
// ... 启动Web服务器等 ...
}
4. 在 Web 服务器中的应用示例
您可以创建一个专门的路由来获取IPv6地址,并在系统信息中包含它。
// Web服务器路由处理函数
void handleGetIPv6() {
server.send(200, "text/plain", getIPv6());
}
// 系统信息JSON生成函数
String getSystemInfoJSON() {
String j = "{";
// ... 其他系统信息 ...
j += "\"ipv4\":\"" + WiFi.localIP().toString() + "\",";
j += "\"ipv6\":\"" + getIPv6() + "\""; // 在JSON中包含IPv6地址
j += "}";
return j;
}
void setup() {
// ...
// 在setup()中设置Web路由
server.on("/ipv6", HTTP_GET, handleGetIPv6);
server.on("/sysinfo", HTTP_GET, handleSysInfo);
// ...
}
如图所示
可以进行ipv6 ddns
评论区(0 条)
发表评论⏳ 加载编辑器…