1

我正在尝试创建一个套接字以允许 IPv4 到 IPv4、IPv4 到 IPv6、IPv6 到 IPv4 和 IPv6 到 IPv6 地址连接。

1.) 协议组合(例如 IPv4 到 IPv6、IPv6 到 IPv4)是否允许?

2.) 如果是这样,我是使用源地址族还是目标地址族来创建套接字?

目前我正在使用源地址,并且在使用 IPv6 源地址和 IPv4 目标地址时收到套接字错误 10014 WSAEFAULT。

代码的相关部分:

if ( !strchr( srcAddr, '[' ) )
    sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
else
    sock = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP );

if ( !strchr( srcAddr, '[' ) )
{
    rc = bind( sock, ( struct sockaddr * ) &sAddrSrc, 
        sizeof( sAddrSrc ) );
}
else
{
    rc = bind( sock, ( struct sockaddr * ) &sAddrSrc6, 
        sizeof( sAddrSrc6 ) );
}

if ( !strchr( destAddr, '[' ) )
{
    rc = connect( sock, (struct sockaddr *) &sAddrDest, 
        sizeof(sAddrDest) );
}
else
{
    rc = connect( sock, ( struct sockaddr * ) &sAddrDest6, 
        sizeof( sAddrDest6 ) );
}
4

2 回答 2

2

您可以使用 IPv6 套接字连接到 IPv4 地址或 IPv6 地址。IPv4 套接字只能连接到 IPv4 目标。在服务器端,IPv6 套接字可以接受来自 IPv6 或 IPv4 的连接,而 IPv4 套接字只能接受 IPv4 连接。

你真的应该避免自己解析地址,使用getaddrinfo. 但是,它不会解析[],因此您必须先提取其中的部分。getaddrinfo会告诉您应该使用 IPv4 套接字还是 IPv6 套接字,但是如果您总是想使用 IPv6,您可以设置ai_familyAF_INET6然后添加AI_V4MAPPEDai_flags. 在这种情况下,如果需要,返回的地址将是::ffff:IPv4IPv6 套接字连接到 IPv4 目标所需的地址。

在服务器端,使用 IPv6 套接字,然后确保调用setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof(int))以使其同时接受 IPv6 和 IPv4 连接。(请注意,MSVC 可能不接受这种 C99 语法。)

话虽如此,如果您已经调用了与 IPv4 源的绑定,则无法连接到 IPv6 目标,反之亦然,但如果您不在连接端调用绑定,或者等待选择,则答案适用在调用 getaddrinfo 之前要绑定什么地址。

于 2012-07-05T22:06:32.137 回答
2

不,您不能连接到与您的套接字配置的地址系列不同的地址系列。IPv6 和 IPv4 使用不同的网络堆栈,因此如果您尝试连接到 IPv6 端点,那么您也必须使用 IPv6 作为源地址。

在您的情况下,如果要连接到一个 IPv4 地址和另一个用于 IPv6 地址,则需要 2 个套接字。

在服务器端,还需要 2 个套接字来监听 IPv4 和 IPv6。两个套接字可以绑定到相同的端口号(因为它们都是不同的网络堆栈),但它们将侦听不同的 IP 地址。

这本电子书是 IPv4 和 IPv6 路由的非常好的参考:Microsoft Windows 的 Tcp/IP 基础知识

于 2012-07-05T22:07:26.483 回答