曲径通幽论坛

标题: inet_pton() -- 将 IPv4/IPv6 地址从 text 转换到二进制形式 [打印本页]

作者: beyes    时间: 2012-6-8 23:29
标题: inet_pton() -- 将 IPv4/IPv6 地址从 text 转换到二进制形式
为了方便阅读,我们平时看到的是点分十进制的 IPv4 地址和以冒号分隔的 IPv6  地址。但是在网络上,编程里传输的不能是这两种形式,而是必须先转换为二进制形式,inet_pton() 函数所做的事情正是如此。函数定义如下:
[Plain Text] 纯文本查看 复制代码
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);

第 1 个参数 af 要么是 AF_INET,要么是 AF_INET6,前者表示转换的是 IPv4 地址,后者表示转换的是 IPv6 地址。
第 2 个参数 src 可以是点分十进制的 IPv4 地址形式,也可以是以冒号分隔的 IPv6 地址形式。
第 3 个参数 dst 用来存储转换后的二进制形式。

测试代码:
[C++] 纯文本查看 复制代码
#include <arpa/inet.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>

       int
       main(int argc, char *argv[])
       {
         struct in_addr addr4;
           struct in6_addr addr6;

           int domain, s, i;
           char str[INET6_ADDRSTRLEN];

           if (argc != 3) {
               fprintf(stderr, "Usage: %s {i4|i6|<num>} string\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           domain = (strcmp(argv[1], "i4") == 0) ? AF_INET :
                    (strcmp(argv[1], "i6") == 0) ? AF_INET6 : atoi(argv[1]);
      
       if (domain == 4 || domain == AF_INET) {
        domain = AF_INET;
            s = inet_pton(domain, argv[2], &addr4);
                if (s <= 0) {
                    if (s == 0)
                       fprintf(stderr, "Not in presentation format");
                    else
                       perror("inet_pton");
                 
                    exit(EXIT_FAILURE);
               }
         
              fprintf(stdout, "Network byte order: %u\n",addr4.s_addr);
      }
      else if (domain == 6 || domain == AF_INET6) {
        domain = AF_INET6;
            s = inet_pton(domain, argv[2], &addr6);
                if (s <= 0) {
                    if (s == 0)
                       fprintf(stderr, "Not in presentation format");
                    else
                       perror("inet_pton");
                 
                    exit(EXIT_FAILURE);
               }
                  fprintf(stdout, "Network byte order: ");
         for (i = 0; i < 16; i++)
            fprintf(stdout, "%u ", addr6.__in6_u.__u6_addr8);
        printf ("\n");  
    }

      else {
          fprintf(stderr, "Usage: %s {i4|i6|<num>} string\n", argv[0]);
          exit(EXIT_FAILURE);
      }
   

    if (domain == AF_INET) {
           if (inet_ntop(domain, &addr4, str, INET6_ADDRSTRLEN) == NULL) {
               perror("inet_ntop");
               exit(EXIT_FAILURE);
           }
           printf("%s\n", str);
    } else if (domain == AF_INET6) {
           if (inet_ntop(domain, &addr6, str, INET6_ADDRSTRLEN) == NULL) {
               perror("inet_ntop");
               exit(EXIT_FAILURE);
           }
           printf("%s\n", str);
    }
      

           exit(EXIT_SUCCESS);
  }

代码中  INET6_ADDRSTRLEN 在netinet/in.h (该头文件由 arpa/inet.h 文件包含)文件中被定义为: #define INET6_ADDRSTRLEN 46 。

结构 struct in_addr 的定义为:
[C++] 纯文本查看 复制代码
/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };


结构 struct in6_addr 定义为:
[C++] 纯文本查看 复制代码
/* IPv6 address */
struct in6_addr
  {
    union
      {
        uint8_t __u6_addr8[16];
#if defined __USE_MISC || defined __USE_GNU
        uint16_t __u6_addr16[8];
        uint32_t __u6_addr32[4];
#endif
      } __in6_u;
#define s6_addr                 __in6_u.__u6_addr8
#if defined __USE_MISC || defined __USE_GNU
# define s6_addr16              __in6_u.__u6_addr16
# define s6_addr32              __in6_u.__u6_addr32
#endif
  };

其中 uint8_t 被定义为 unsigned char 类型,如果要用 printf() 函数来打印该类型,格式控制符为 %u 。

运行输出:
# ./inet_pton i6 1:0:0:0:0:0:0:8
Network byte order: 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 8
1::8
# ./inet_pton i6 0:0:0:0:0:FFFF:204.152.189.116
Network byte order: 0 0 0 0 0 0 0 0 0 0 255 255 204 152 189 116
::ffff:204.152.189.116
# ./inet_pton i4 184.22.147.23
Network byte order: 395515576
184.22.147.23
关于 IPV6 的地址记录介绍可参考:《IPv6 记法 》。




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2