【问题标题】:Efficient way to store IPv4/IPv6 addresses存储 IPv4/IPv6 地址的有效方法
【发布时间】:2014-12-19 07:46:56
【问题描述】:

我正在开发一个 C/C++ 网络项目,它应该能够同时使用 IPv4 和 IPv6 网络堆栈。 该项目仅适用于 Linux。 因此,我试图找到一种有效的方法来存储 IP 地址并区分协议系列。 第一种方法是建立一个联合:

struct ip_addr {
   uint8_t fam; // socket family type
   union {
       struct in_addr ipv4_sin_addr;
       struct in6_addr ipv6_sin_addr;
   } addr;
};
第二种方法是定义一个`typedef std::vector IPAddressNumber`并在向量的字节数之后产生差异。

第三种方法是使用 gcc 中的 int128_t/uint128_t 或 __int128_t。

对于最后一种情况,我想知道这些类型是从哪个 GCC 版本支持的,适用于哪些平台(尤其是 IA-32/IA-64)以及是否存在任何已知错误。另外,以上哪种解决方案可能是最方便的?

【问题讨论】:

  • 我不确定int128_t 是否需要或是否适合 IPv6 地址。 Posix 在其 API 中提供了其他类型。对于 GCC,最好使用最新版本(2014 年 10 月的 GCC 4.9.1)并尽可能使用 C++11。
  • 我还建议使用struct sockaddr_in6 结构来处理 IPv6 地址。
  • 您很少将 IP 地址用作实数(除了它们需要按网络字节顺序提供)。再说一遍:使用uint128_t 表示 IPv6 地址可能是一个非常糟糕的主意
  • struct sockaddr_storage 可用于与家庭无关的存储,它很方便,从定义上来说并不节俭。

标签: c++ gcc ipv6 ipv4 int128


【解决方案1】:

正如1st answer 中所述,自 GCC 4.6.4 起提供 128 位整数支持。

您的问题不是 128 位整数支持,而是如何正确表示 IPv6 地址
对此的正确答案是使用socket API 提供的struct 定义。

这些可用于 IPv6 堆栈的各种操作系统实现并已标准化。
此外,您无需担心使用这些的效率。对齐打包将正常工作,您不必关心实际表示的字节顺序与网络字节顺序问题。


至于您的编辑:

您不必重新发明轮子!已经有适当的struct 定义可用,以正确地尊重AF_xxx 系列类型。

查看这些资源以获得更详细的说明:

我们在生产中有一个IpAddr 类,它使用不透明的sockaddr_in*sockaddr_in6* 指针来封装基于sockaddr* 指针的IPv4 或IPv6 地址,以及基于@987654337 的reinterpret_cast<> @结构成员。

【讨论】:

  • 我实际上看到了一个开源项目 (chromium),它使用与您提到的类似的表示:它使用一个名为 SockaddrStorage [1] 的结构和一个名为 IPEndPoint 的类,该类与该结构一起使用。这个结构的问题在于,当您还有一个端口或您打算创建一个套接字(例如: bind 、 connect 调用)而不仅仅是用于存储 ip 时,它很有用。 [1] goo.gl/hSyW8o
  • 我需要一种内部方法来存储从字符串表示(即:从标志或环境变量)转换后的 ip。我发现使用 struct ip_addr 表示更有用,因为它更方便调用 inet_ntop/inet_pton 不能使用 sockaddr(单独而不是作为指针),因为 sa_data 字段不足以存储 IPv6 地址。
  • @evelina “我需要一种内部方法来存储从字符串表示形式(即:从标志或环境变量)转换后的 ip。” 好吧,我不明白,您实际上在为 效率 烦恼什么。上述结构将很好地代表 IP 协议相关类型。
  • 不错的答案。使用它。
【解决方案2】:

根据this thread__int128_t__uint128_t 是在4.2 版左右引入的。并且根据 GCC 的文档 __int128 及其未签名的对应 unsigned __int128GCC 4.6.4 以来得到支持。

请注意,不可移植的 128 位整数绝对不是适合保存和使用 IPv6 地址的类型。正如 cmets 中提到的,有一些特殊的数据结构,比如sockaddr_in6

【讨论】:

  • 嗯,这回答了对 128 位整数的支持,但恐怕这不是表示 IPv6 地址的正确数据类型:-/ ...
  • 我现在已经给出了自己的答案,因为已经被告知了。但是是的,指出 Y 问题可以改善你的答案。
  • @Loopunroller 谢谢你的回答!我添加了有关我的问题的更多信息。
【解决方案3】:

此代码来自 nginx。这与第一个答案相同。 我认为使用指针 sockaddr_in* 不是一个好主意。

typedef union {
    struct sockaddr           sockaddr;
    struct sockaddr_in        sockaddr_in;
#if (NGX_HAVE_INET6)
    struct sockaddr_in6       sockaddr_in6;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
    struct sockaddr_un        sockaddr_un;
#endif
} ngx_sockaddr_t;

https://github.com/nginx/nginx/blob/912fb44e25c6ab2598e36b4544c709b871251b2e/src/core/ngx_inet.h#L44

【讨论】:

    猜你喜欢
    • 2016-09-18
    • 2014-08-03
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 2011-03-28
    • 2013-09-18
    • 2012-05-22
    • 2012-12-25
    相关资源
    最近更新 更多