网络编程函数inet_pton 与 inet_ntop函数的妙用

387 阅读2分钟

首先阅读一下man手册

对于IPV4地址

IPv4 network address in dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number of up to three digits in the range 0 to 255. The address is converted to a struct in_addr and copied to dst, which must be sizeof(struct in_addr) (4) bytes (32 bits) long.

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };

对于IPv6地址

src points to a character string containing an IPv6 network address. The address is converted to a struct in6_addr and copied to dst, which must be sizeof(struct in6_addr) (16) bytes (128 bits) long.

#ifndef __USE_KERNEL_IPV6_DEFS
/* 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
  };
#endif /* !__USE_KERNEL_IPV6_DEFS */

返回值

RETURN VALUE

returns 1 on success (network address was successfully converted).  
returns 0 is returned if src does not contain a character string rep‐resenting a valid network address in the specified address family.  
If af does not contain a valid address family, -1 is returned and errno is set to EAFNOSUPPORT.

IPV4代码示例:

// 测试IPv4
void testipv4()
{   
    /* convert buffer cache */
    char buf[128] = {0};
    char sip4[128] = "11.12.13.14";
    struct in_addr address;
    
    /* ip地址转网络字节序 */
    int ret = inet_pton(AF_INET, (const char *)sip4, (void *)&(address));  
    if (ret != 1)
    {
        perror("inet_pton convert error.");
    }
    printf("address.s_addr:%d\tHEX:0X%x\n", address.s_addr, address.s_addr);

    /* 网络字节序转ip地址 */
    const char * result = inet_ntop(AF_INET, &address, buf, sizeof(buf));
    if(!result)
    {
        perror("inet_ntop convert error.");
    }
    else
    {
        printf("buf:%s\n", buf);
        printf("result:%s\n", result);
    }
}

IPV6的代码示例

// 测试IPv6
void testipv6()
{
    /* convert buffer cache */
    char buf[128] = {0};
    char sip6[128] = "2222:8888:6666:3333:1319:2222:3333:6666";

    struct in6_addr address;
    int ret = inet_pton(AF_INET6, (const char *)sip6, (void *)&(address));  
    if (ret != 1)
    {
        perror("inet_pton convert error.");
    }

    const char * result = inet_ntop(AF_INET6, (void *)&address, buf, sizeof(buf));
    if(!result)
    {
        perror("inet_ntop convert error.");
    }
    else
    {
        printf("buf:%s\n", buf);
        printf("result:%s\n", result);
    }
}

使用联合体的方式合理的使用地址转换函数

需求:对于下面的结构体 如果是IPv4地址 放在m_sip的后4字节.

typedef struct NP_FLEX_RULE_TX_TABLE_KEY_T
{
    UCHAR   m_sip[16];            /* 16B      */
    UCHAR   m_dip[16];            /* 16B      */
    USHORT  m_sport;             /* 2B       */
    USHORT  m_dport;             /* 2B       */
    UINT8   m_proto;             /* 1B       */
    UINT8   m_mode;              /* 1B       */
}__attribute__((packed)) NP_FLEX_RULE_TX_TABLE_KEY_T;

解决方案:

1.定义联合体16Bytes

typedef union
{
    uint8_t  v6[16];
    uint32_t v4[4];
    uint64_t v64[2];
} IP_ADDR_T;

void testIP()
{
    int ret = 0;
    char buf[128] = {0};
    /* loop variable */
    int idx = 0;
    char sip4[128] = "11.12.13.14";
    char sip6[128] = "2222:8888:6666:3333:1319:2222:3333:6666";
    NP_FLEX_RULE_TX_TABLE_KEY_T key;
    memset(&key, 0, sizeof(NP_FLEX_RULE_TX_TABLE_KEY_T));
    /* 使用联合体 */
    IP_ADDR_T address;
    memset(&address, 0, sizeof(IP_ADDR_T));
    IPTYPE iptype = appointIP(sip6);
    if (iptype == NEITHER)
    {
        perror("ip address invaild.\n");
        return;
    }
    else if(iptype == IP4)
    {
        ret = inet_pton(AF_INET, (const char *)sip4, (void *)&(address));  
        if (ret != 1)
        {
            perror("inet_pton convert error.");
        }
        key.m_mode = IP4;
        memcpy(key.m_sip + 12, &(address.v4[0]), sizeof(uint8_t) * 4);

        for(idx = 0; idx < 4; ++idx)
        {
            printf("address.v4[%d]:0X%x\n", idx, address.v4[idx]);
        }
    }
    else if(iptype == IP6)
    {
        ret = inet_pton(AF_INET6, (const char *)sip6, (void *)&(address));  
        if (ret != 1)
        {
            perror("inet_pton convert error.");
        }
        key.m_mode = IP6;
        memcpy(key.m_sip, address.v6, sizeof(uint8_t) * 16);
        for(idx = 0; idx < 4; ++idx)
        {
            printf("0X%x\t", address.v4[idx]);
        }
        printf("\n");
    }

    uint8_t mode = key.m_mode;
    if (mode == IP4)
    {
        const char * result = inet_ntop(AF_INET, &(address.v4[0]), buf, sizeof(buf));
        if(!result)
        {
            perror("inet_ntop convert error.");
        }
        else
        {
            printf("buf:%s\n", buf);
            printf("result:%s\n", result);
        }
    }
    else if(mode == IP6)
    {
        const char * result = inet_ntop(AF_INET6, (void *)&address, buf, sizeof(buf));
        if(!result)
        {
            perror("inet_ntop convert error.");
        }
        else
        {
            printf("buf:%s\n", buf);
            printf("result:%s\n", result);
        }
    }
}