【问题标题】:Is there any difference between IPv4 and IPv6 at the socket level?IPv4 和 IPv6 在套接字级别有什么区别吗?
【发布时间】:2010-03-01 15:38:36
【问题描述】:

我需要将 IPv6 支持添加到当前仅支持 IPv4 的现有基于套接字的应用程序中。为了迎接即将到来的 IPv6 时代,有人命令我为应用程序添加 IPv6 接口,让外界在尝试与应用程序通信时选择 IPv4 接口或 IPv6 接口。

我的问题是:对于 Linux 中的套接字处理 API 级别,处理基于 IPv4 的套接字和基于 IPv6 的套接字之间是否没有区别?

更进一步,是否可以让套接字监听具有相同端口的两个 IP 地址?如果这是真的,那么我想实现这个需求是一件微不足道的工作。

【问题讨论】:

    标签: linux sockets


    【解决方案1】:

    不可能使用 1 个 TCP 套接字监听 2 个不同的 IP 地址,但是如果您使用 in6addr_any 地址监听所有接口,那也将包括所有 IPv4 地址(尽管我相信例如 linux 有一个内核禁用该映射的选项)。

    (较新版本的)套接字 API 对于您使用的是 IPv4 还是 IPv6 非常透明,但必须非常小心地了解 IPv4 应用程序的典型编码方式。

    例如这个接受连接并打印出远程主机地址的 IPv4 代码:

     struct sockaddr_in client_addr;
     socklen_t addr_len = sizeof(client_addr);
     client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len);
     log_printf("New client from %s\n",inet_ntoa(client_addr.sin_addr.s_addr));
    

    必须转换为以下内容,同时处理 IPv4 和 IPv6

     struct sockaddr_storage client_addr;
     char numeric_addr[INET6_ADDRSTRLEN];
     socklen_t addr_len = sizeof(client_addr);
     client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len);
     if(client_addr.ss_family == AF_INET)
        log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in*)&client_addr)->sin_addr.s_addr ,numeric_addr,sizeof numeric_addr));
     else if(client_addr.ss_family == AF_INET6)
        log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in6*)&client_addr)->sin6_addr ,numeric_addr,sizeof numeric_addr));
    

    虽然我相信你可以使用getaddrinfo() 做得更加优雅和透明

    以下是有关 IP 层独立性的附加说明: http://uw714doc.sco.com/en/SDK_netapi/sockC.PortIPv4appIPv6.html http://www.kame.net/newsletter/19980604/

    【讨论】:

    • @nos :感谢您的帮助。我还有一个问题,是否可以将一个 udp 套接字绑定到多个 IP 地址?例如,一个用于 ipv4,一个用于 ipv6,总共 2 个。
    • 不,您也不能将 UDP 套接字绑定到超过 1 个(或全部)的 IP 地址。不过,您可以使用 SCTP,利用其多宿主功能。对于 TCP 或 UDP,您必须为每个要监听的地址创建 1 个套接字,除非您想监听所有 IP 地址
    • 要获得双栈套接字,有一个套接字选项可以启用或禁用双栈行为 - 搜索 IPV6_V6ONLY 以获取更多信息。如果您不这样做,您的程序将在某些操作系统、特定版本上神秘地失败。
    【解决方案2】:

    对于 IPv4 和 IPv6,大部分套接字处理是相同的。在服务器上,一旦您绑定了地址,对listenacceptrecvsend 的调用对于 IPv4 和 IPv6 连接都将同样有效。

    但是任何处理地址的函数,例如connectbindgetsocknamegetpeername,都需要修改,因为您需要使用sockaddr_in6。此外,您需要修改使用地址的函数(例如,对inet_addr 的调用需要更改为inet_pton)。

    在 Linux 上,如果您绑定到 in6addr_any,则与该端口的 IPv4 和 IPv6 连接都将起作用(尽管这可能会侦听 2 个以上的地址,因为它还将侦听 IPv4 环回 127.0.0.1 和 IPv6环回::1)。但是在 Windows 上,我一直无法让它工作,我需要在一个套接字上监听 IPv4 和另一个套接字来监听 IPv6。

    【讨论】:

    • 在 Windows 中,通过重新设计的双栈套接字堆栈架构,在 Vista 中引入了单个套接字在单个端口上侦听和接受 IPv4 和 IPv6 客户端的能力。创建一个 IPv6 侦听套接字并将新的 IPV6_V6ONLY 套接字选项设置为 False 以允许 IPv4 客户端在其上。
    • @RemyLeabeauTeamB - 谢谢 - 这些信息很有帮助。
    【解决方案3】:

    Beej 的网络编程指南解决了 IPv4 和 IPv6 编码的差异。 http://beej.us/guide/bgnet/

    他专门用一节来更改您现有的 IPv4 代码以处理 IPv6。

    他还解释了如何在套接字级别进行抽象编码,这样您就不需要知道您是在处理 IPv4 地址还是 IPv6。

    【讨论】:

      【解决方案4】:

      我认为有区别,主要是如何分配/显示 IP 地址和子网掩码。

      采用传入 IPv4 地址的方法将不起作用并在为它们提供纯 IPv6 时引发异常,因此您的方法将需要检查启动了哪种连接,除了我不这么认为.

      【讨论】:

        【解决方案5】:

        IPv6 是 128 位地址空间,与IPv4(32 位)相比,提供更多功能(无状态、多播、更简单的路由器处理等),IPv4 的地址空间即将耗尽,但在 NAT/SNAT 的帮助下,它可能会增加 IPv4 协议的寿命。使用 IPv6 取决于操作系统是否支持新协议。它当然可以在 Windows 7、Linux 上使用...主要是 IPv6 向后兼容 IPv4...

        要回答您的问题,这取决于操作系统可以支持 IPv6 网络堆栈的 API 级别,以下是在 MSDN 上找到的 IPv6 套接字示例示例,对于 Linux,套接字的使用主要是除了您将使用sockaddr_in6...

        希望这会有所帮助, 此致, 汤姆。

        【讨论】:

          猜你喜欢
          • 2017-02-10
          • 2010-12-28
          • 1970-01-01
          • 2013-09-05
          • 2018-05-09
          • 1970-01-01
          • 2018-02-19
          • 2020-10-23
          相关资源
          最近更新 更多