我正在试验IPv6套接字,特别是Windows和更高版本提供的“双堆栈”功能,以及默认情况下在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:连接被拒绝。
如果我更改要绑定到::(或将空主机传递给getaddrinfo() (相同的事情))的服务器代码,并更改客户端代码以在getaddrinfo()调用中指定空主机,则V4客户端可以很好地连接。
有人能解释一下为什么吗?如果我们想要双套接字行为,我还没有读到必须指定空主机(因此使用INADDR_ANY)的任何内容。这不可能是一个要求,因为我有一个多宿主,并且我只想在一些可用的IP上接受IPv4?
编辑15/05/2013:
这是相关的文档,使我对为什么我的代码失败感到困惑:
"Windows和以后的版本提供了创建一个IPv6套接字的能力,该套接字可以同时处理IPv6和IPv4通信。例如,为IPv6创建一个TCP侦听套接字,并将其放入双堆栈模式,并绑定到端口5001。此双堆栈套接字可以接受从连接到端口5001的IPv6 TCP客户端和连接到端口5001的IPv4 TCP客户端的连接。“ 默认情况下,在Windows上创建的IPv6套接字只在IPv6协议上运行。为了使IPv6套接字成为双堆栈套接字,必须使用IPV6_V6ONLY套接字选项调用setsockopt函数,以便在套接字绑定到IP地址之前将该值设置为零。当IPV6_V6ONLY套接字选项设置为零时,为AF_INET6地址系列创建的套接字可用于向IPv6地址或IPv4映射地址发送和接收数据包。(重点为我)。
发布于 2013-05-10 12:14:13
IPv4和IPv6是两个独立的协议。一个协议的数据包不能使用另一个协议来处理。这就是为什么双重堆栈的概念存在的原因:您的系统同时运行IPv4和IPv6协议栈,同时具有IPv4和IPv6地址等。
操作系统有一个窍门,您可以使用IPv6套接字侦听所有IPv4和IPv6地址。您仍然需要在主机上同时拥有两个地址家族,并且只有在绑定到通配符地址时才能工作。一旦您将该套接字绑定到一个不再工作的固定地址,它将只对绑定到的地址起作用。
因此,如果要侦听所有可用地址,则将IPV6_V6ONLY设置为0并侦听通配符地址。IPv4客户机将显示为使用以::ffff:开头的IPv6地址,最后32位包含IPv4地址。
当要绑定到特定地址时,需要将套接字绑定到要侦听的每个地址。然后,您需要使用select(...)来监视这些套接字,并响应那些因为有人连接到它们而变得活跃的套接字。
发布于 2015-03-08 10:05:32
此链接v1.3/ch12lev1sec2.html提供了有关IPv4和IPv6连接的更多信息,
大多数双堆栈主机在处理侦听套接字时应使用以下规则:
https://stackoverflow.com/questions/16480729
复制相似问题