我与IPv6的试验插座,默认情况下在Windows Vista及更高版本,显然在Unix提供特别是“双栈”的能力。 我发现,当我在我的服务器绑定到特定的IP地址,或以我的本地机器的主机名解析,我不能接受一个IPv4客户端的连接。 当我然而绑定到INADDR_ANY,我可以。
请考虑我的服务器下面的代码。 你可以看到,我按照创建一个IPv6套接字,那么IPV6_V6ONLY标志设置为零的微软的建议是:
addrinfo* result, *pCurrent, hints;
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // We intend to use the addrinfo in a call to connect(). (I know it is ignored if we specify a server to connect to...)
int nRet = getaddrinfo("powerhouse", "82", &hints, &result);
SOCKET sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
int no = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) != 0)
return -1;
if (bind(sock, result->ai_addr, result->ai_addrlen) == SOCKET_ERROR)
return -1;
if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
return -1;
SOCKET sockClient = accept(sock, NULL, NULL);
这里是我的客户端代码。 你可以看到我创建IPv4套接字,并尝试连接到我的服务器:
addrinfo* result, *pCurrent, hints;
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo("powerhouse", "82", &hints, &result) != 0)
return -1;
SOCKET sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
int nRet = connect(sock, result->ai_addr, result->ai_addrlen);
从我的连接调用的结果总是10061:连接被拒绝。
如果我改变我的服务器代码绑定到::(或传递一个NULL主机的getaddrinfo()(同样的事情)),并改变我的客户端代码可以指定在的getaddrinfo()调用一个NULL主机,则V4客户端可以连接精细。
任何人都可以解释为什么吗? 我没有看到任何东西,我们必须指定一个NULL主机(因此使用INADDR_ANY)如果我们想双插槽的行为。 这不可能是一个要求,因为我有一个多宿主主机,我想接受的IPv4上只有部分可用IP的?
编辑15/05/2013:
这是已经得到了我的困惑,为什么我的代码失败的相关文件:
从双栈套接字IPv6的Winsock应用程序
“Windows Vista和更高版本提供了创造,它可以处理IPv6和IPv4流量的一个IPv6套接字的能力。例如,对IPv6的TCP监听套接字的建立,投入双栈模式,并绑定到端口5001。这双堆栈插座可以接受来自IPv6的TCP客户端连接到端口5001和从IPv4 TCP客户端的连接连接到端口5001。”
“默认情况下,在Windows Vista中创建和更高版本IPv6套接字工作在IPv6协议。为了使IPv6套接字成双栈插座,setsockopt函数必须与IPV6_V6ONLY套接字选项调用这个值设置为零点前的套接字绑定到一个IP地址。 当IPV6_V6ONLY套接字选项设置为零,为AF_INET6地址族创建的套接字可用于发送和接收数据包,并从IPv6地址或IPv4映射地址。(重点煤矿)”