首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将IPv4客户端连接到IPv6服务器:拒绝连接

将IPv4客户端连接到IPv6服务器:拒绝连接
EN

Stack Overflow用户
提问于 2013-05-10 10:57:01
回答 2查看 18.5K关注 0票数 7

我正在试验IPv6套接字,特别是Windows和更高版本提供的“双堆栈”功能,以及默认情况下在Unix上提供的功能。我发现,当我将服务器绑定到特定的IP地址或本地机器的主机名解析时,我无法接受来自IPv4客户端的连接。但是,当我绑定到INADDR_ANY时,我可以。

请考虑我的服务器的下列代码。您可以看到,我遵循微软关于创建IPv6套接字的建议,然后将IPV6_V6ONLY标志设置为零:

代码语言:javascript
复制
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套接字并试图连接到我的服务器:

代码语言:javascript
复制
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:

这是相关的文档,使我对为什么我的代码失败感到困惑:

来自用于IPv6 Winsock应用程序的双栈套接字

"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映射地址发送和接收数据包。(重点为我)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-10 12:14:13

IPv4和IPv6是两个独立的协议。一个协议的数据包不能使用另一个协议来处理。这就是为什么双重堆栈的概念存在的原因:您的系统同时运行IPv4和IPv6协议栈,同时具有IPv4和IPv6地址等。

操作系统有一个窍门,您可以使用IPv6套接字侦听所有IPv4和IPv6地址。您仍然需要在主机上同时拥有两个地址家族,并且只有在绑定到通配符地址时才能工作。一旦您将该套接字绑定到一个不再工作的固定地址,它将只对绑定到的地址起作用。

因此,如果要侦听所有可用地址,则将IPV6_V6ONLY设置为0并侦听通配符地址。IPv4客户机将显示为使用以::ffff:开头的IPv6地址,最后32位包含IPv4地址。

当要绑定到特定地址时,需要将套接字绑定到要侦听的每个地址。然后,您需要使用select(...)来监视这些套接字,并响应那些因为有人连接到它们而变得活跃的套接字。

票数 8
EN

Stack Overflow用户

发布于 2015-03-08 10:05:32

此链接v1.3/ch12lev1sec2.html提供了有关IPv4和IPv6连接的更多信息,

大多数双堆栈主机在处理侦听套接字时应使用以下规则:

  • 监听IPv4套接字只能接受来自IPv4客户端的传入连接.
  • 如果服务器具有绑定通配符地址的侦听IPv6套接字并没有设置IPV6_V6ONLY套接字选项(第7.8节),则该套接字可以接受来自IPv4客户端或IPv6客户端的传入连接。对于来自IPv4客户端的连接,服务器用于连接的本地地址将是对应的IPv6 4映射的IPv6地址。
  • 如果服务器具有一个侦听IPv6套接字,该套接字绑定了IPv4 4映射的IPv6地址以外的IPv6地址,或者绑定了通配符地址,但设置了IPv6_V6ONLY套接字选项(第7.8节),则该套接字只能接受来自IPv6客户端的传入连接。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16480729

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档