更改 IPv6 Winsock 应用程序的数据结构
添加对 IPv6 的支持时,必须确保应用程序定义大小正确的数据结构。 IPv6 地址的大小比 IPv4 地址大得多。 存储 IP 地址时硬编码以处理 IPv4 地址大小的结构将导致应用程序中出现问题,必须对其进行修改。
最佳做法
确保结构大小正确的最佳方法是使用 SOCKADDR_STORAGE 结构。 SOCKADDR_STORAGE结构与 IP 地址版本无关。 当 SOCKADDR_STORAGE 结构用于存储 IP 地址时,可以使用一个基本代码正确处理 IPv4 和 IPv6 地址。
以下示例是从附录 B 的 Server.c 文件中摘录的,它标识了对 SOCKADDR_STORAGE 结构的适当用途。 请注意,正如本示例所示,如果使用得当,该结构可以很好地处理 IPv4 或 IPv6 地址。
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#define BUFFER_SIZE 512
#define DEFAULT_PORT "27015"
int main(int argc, char **argv)
{
char Buffer[BUFFER_SIZE] = {0};
char *Hostname;
int Family = AF_UNSPEC;
int SocketType = SOCK_STREAM;
char *Port = DEFAULT_PORT;
char *Address = NULL;
int i = 0;
DWORD dwRetval = 0;
int iResult = 0;
int FromLen = 0;
int AmountRead = 0;
SOCKADDR_STORAGE From;
WSADATA wsaData;
ADDRINFO *AddrInfo = NULL;
ADDRINFO *AI = NULL;
// Parse arguments
if (argc >= 1) {
Hostname = argv[1];
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
From.ss_family = (ADDRESS_FAMILY) Family;
//...
return 0;
}
注意
SOCKADDR_STORAGE 结构是 Windows XP 的新增功能。
要避免的代码
通常,许多应用程序使用 sockaddr 结构存储与协议无关的地址,或 IP 地址的 sockaddr_in 结构。 sockaddr 结构和 sockaddr_in 结构都不够大,无法容纳 IPv6 地址,因此,如果应用程序要兼容 IPv6,两种结构都不够大。
编码任务
将现有代码库从 IPv4 修改为 IPv4 和 IPv6 互操作性
- 获取 Checkv4.exe 实用工具。 该工具包含在 Microsoft Windows 软件开发工具包 (SDK) 中。
- 针对代码运行“Checkv4.exe”实用工具。 了解如何在使用 Checkv4.exe 实用工具部分中针对文件运行 Checkv4.exe 实用工具。
- 该实用工具提醒您使用 sockaddr 或 sockaddr_in 结构,并提供有关如何将 IPv6 兼容结构替换为 SOCKADDR_STORAGE 的建议。
- 根据需要替换任何此类实例和关联代码,以使用 SOCKADDR_STORAGE 结构。
或者,您可以在代码库中搜索 sockaddr 和 sockaddr_in 结构的实例,并根据需要将所有这些用法(以及其他关联的代码)更改为 SOCKADDR_STORAGE 结构。
注意
addrinfo 和 SOCKADDR_STORAGE 结构分别包括协议和地址家庭成员(ai_family 和 ss_family)。 RFC 2553 将 addrinfo 的 ai_family 成员指定为 int,而 ss_family 指定为短;因此,这些成员之间的直接复制会导致编译器错误。
相关主题