之前遇到過要自己實現inet_aton和inet_ntoa函數功能的問題,這裡總結一下。
1 基本知識
網路位元組序是大端模式,那麼記憶體中的低地址存放的是資料的高位,記憶體中的高地址存放的是資料的低位。 inet_aton是將IPv4地址(點分法)轉換成對應的十進位整數;而inet_ntoa是將十進位整數轉換成對應的IPv4地址(點分法)。
2 完整代碼
#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 *) ∈
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.