TypeCodes

自己实现inet_aton和inet_ntoa函数功能

之前遇到过要自己实现inet_atoninet_ntoa函数功能的问题,这里总结一下。

1 基本知识

网络字节序是大端模式,那么内存中的低地址存放的是数据的高位,内存中的高地址存放的是数据的低位。 inet_aton是将IPv4地址(点分法)转换成对应的十进制整数;而inet_ntoa是将十进制整数转换成对应的IPv4地址(点分法)。

2 完整代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
 * @FileName    network_selfdefine.c
 * @Describe    A simple example for using sigprocmask and sigsuspend functions in linux.
 * @Author      vfhky 2016-04-08 13:11 https://typecodes.com/cseries/networkselfdefineconv.html
 * @Compile     gcc network_selfdefine.c -o network_selfdefine
 */
#include <stdio.h>
#include <ctype.h>
#include "print.h"
#define IP_ADRESS "192.168.1.177"

/*
 * 将IPv4地址(点分法)转换成对应的十进制整数
 * 原函数声明:
 * int inet_aton(const char *cp, struct in_addr *inp);
 */
unsigned int __inet_aton( const char *c_ipaddr )
{
    unsigned int u_ipaddr = 0;
    unsigned int u_tmp = 0;
    char c;
    int i_base = 10;
    int i_shift = 0;
    int i_recycle = 0;

    c = *c_ipaddr;
    while( 1 )
    {
        u_tmp = 0;
        while( 1 )
        {
            //如果是数字
            if( isdigit(c) )
            {
                u_tmp = (u_tmp * i_base) + (c - 0x30);
                c = *++c_ipaddr;
            }
            else
            {
                //如果不是数字而是.符号,说明.符号前面的数据已经处理完毕
                break;
            }
        }

        //字节移位,注意网络字节序是大端模式
        i_shift = 8*i_recycle++;
        u_tmp <<= i_shift;
        u_ipaddr += u_tmp;

        //对点(.)符号的处理
        if( c == '.' )
        {
            c = *++c_ipaddr;
        }
        else
        {
            //如果是其它符号(例如结束符\0等)则跳出整个循环
            break;
        }
    }

    //检查是否包含非结束符、空格等符号,是则返回0
    if( c != '\0' && ( !isspace(c) ) )
        goto ret_0;

    return u_ipaddr;
ret_0:
    return (0);
}

/**
 * 将十进制整数转换成对应的IPv4地址(点分法),其中由于网络字节序是大端表示,所以第一个字节对应的是整数的低位byte[0]
 * 原函数声明:
 * int inet_aton(const char *cp, struct in_addr *inp);
 */
static char buffer[16];
char *  __inet_ntoa( unsigned int in )
{
    unsigned char *bytes = (unsigned char *) &in;
    snprintf( buffer, sizeof (buffer), "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
    return buffer;
}

int main( int argc, char **argv )
{
    PRINT( "IP_ADRESS[%s] ==> [%lu].", IP_ADRESS, __inet_aton( IP_ADRESS ) );
    PRINT( "[%lu]=[0x%x].", __inet_aton( IP_ADRESS ), __inet_aton( IP_ADRESS ) );
    PRINT( "Network orders[%lu] ==> [%s].", __inet_aton( IP_ADRESS ), __inet_ntoa(__inet_aton( IP_ADRESS )) );
    return 0;
}

3 编译执行

使用《Linux C/C++工程中可生成ELF、动/静态库文件的通用Makefile》一文中的Makefile文件进行程序编译(当然也可以使用命令进行编译gcc network_selfdefine.c -o network_selfdefine),接着执行该程序,得到如下图所示的结果:

自己实现inet_aton和inet_ntoa函数功能

需要说明的是从第87行输出的[2969675968]=[0xb101a8c0].可以看出,低字节的0xC0(即192)由于网络字节序大端模式的关系存放在内存中的高位,高字节的0xB1(即177)存放在内存中的低位。

4 附录

关于inet_aton的man说明:

[vfhky@typecodes xlei]$ man inet_aton
INET(3)                         Linux Programmer's Manual                        INET(3)

NAME
       inet_aton,   inet_addr,   inet_network,   inet_ntoa,  inet_makeaddr,  inet_lnaof,
       inet_netof - Internet address manipulation routines

SYNOPSIS
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>

       int inet_aton(const char *cp, struct in_addr *inp);

       in_addr_t inet_addr(const char *cp);

       in_addr_t inet_network(const char *cp);

       char *inet_ntoa(struct in_addr in);

       struct in_addr inet_makeaddr(int net, int host);

       in_addr_t inet_lnaof(struct in_addr in);

       in_addr_t inet_netof(struct in_addr in);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       inet_aton(), inet_ntoa(): _BSD_SOURCE || _SVID_SOURCE

DESCRIPTION
       inet_aton() converts the Internet host address cp from the IPv4  numbers-and-dots
       notation  into binary form (in network byte order) and stores it in the structure
       that inp points to.  inet_aton() returns nonzero if the address is valid, zero if
       not.

关于inet_aton的man说明:

[vfhky@typecodes ~]$ man inet_ntoa
INET(3)                         Linux Programmer's Manual                        INET(3)

NAME
       inet_aton,   inet_addr,   inet_network,   inet_ntoa,  inet_makeaddr,  inet_lnaof,
       inet_netof - Internet address manipulation routines

SYNOPSIS
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>

       int inet_aton(const char *cp, struct in_addr *inp);

       in_addr_t inet_addr(const char *cp);

       in_addr_t inet_network(const char *cp);

       char *inet_ntoa(struct in_addr in);

       struct in_addr inet_makeaddr(int net, int host);

       in_addr_t inet_lnaof(struct in_addr in);

       in_addr_t inet_netof(struct in_addr in);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       inet_aton(), inet_ntoa(): _BSD_SOURCE || _SVID_SOURCE

DESCRIPTION
       inet_aton() converts the Internet host address cp from the IPv4  numbers-and-dots
       notation  into binary form (in network byte order) and stores it in the structure
       that inp points to.  inet_aton() returns nonzero if the address is valid, zero if
       not.

Comments »