inet_aton、inet_addr和inet_ntoa

 

 

地址转换函数:

inet_addr & inet_network

inet_aton & inet_ntoa 和 和inet_pton & inet_ntop

1、先了解一下需要用到的数据类型。

typedef uint32_t in_addr_t;

in_addr_t 这个类型保存的数据,到底是按本机字节序保存的,还是网络字节序保存的,这是不确定的!!!

2、为了解决此问题,Linux 又定义了一个新的结构体类型 struct in_addr,它明确的表示,它保存的 ip 地址就是网络字节序的!!!

struct in_addr {
  in_addr_t s_addr; 
}

如果说你传了一个本机字节序的 unsigned int 类型的整数给 in_addr 的 s_addr 成员,很抱歉,后面使用到该结构体的函数都会出错。

 

3、套接字地址在程序中的表示

这个结构体的样子如下:

struct sockaddr_in {
  sa_family_t    sin_family; /* 这个值固定写 AF_INET */
  in_port_t      sin_port;   /* 网络字节序的端口号 */
  struct in_addr sin_addr;   /* in_addr 类型的 ip 地址 */
};

接下来了解函数

in_addr_t inet_addr(const char *cp);

in_addr_t inet_network(const char *cp);

inet_addr和inet_network函数都是用于将字符串形式转换为整数形式用的,两者区别很小,inet_addr返回的整数形式是网络字节序,而inet_network返回的整数形式是主机字节序。

他俩都有一个小缺陷,那就是当IP是255.255.255.255时,这两个“小子”(对这两个函数的昵称,请谅解…^_^)会认为这是个无效的IP地址,这是历史遗留问题,其实在目前大部分的路由器上,这个255.255.255.255的IP都是有效的。

在Unix网络编程中,我们常用到地址转换函数,它将ASCII字符串(如"206.62.226.33")与网络字节序的二进制值(这个值保存在套接口地址结构中)间进行地址的转换。

  1、inet_aton、inet_addr和inet_ntoa在点分十进制数串(例如"206.62.226.33")与它的32位网络字节序二进制值间转换IPv4地址。

  2、两个较新的函数:inet_pton和inet_ntop对IPv4和IPv6地址都能进行处理。

 

 1 #include<arpa/inet.h>
 2 
 3 /* 返回1:串有效,返回0:串出错 */
 4 int inet_aton(const char *strptr, struct in_addr *addrptr);
 5 
 6 /* 若成功,返回32位二进制的网络字节序地址;若出错,返回INADDR_NONE */
 7 in_addr_t inet_addr(const char *strptr);
 8 
 9 /* 返回指向点分十进制数串的指针 */
10 char* inet_ntoa(struct in_addr inaddr);

 

  inet_aton将strptr所指的C字符转换为32位网络字节序二进制值,并用一个出参addrptr来存储,返回值为1代表成功,否则返回0。

  inet_addr与inet_aton不同在于,他的返回值为转换后的32位网络字节序二进制值,而不是作为出参返回,这样存在一个问题,他的返回值返回的有效IP地址为0.0.0.0到255.255.255.255,如果函数出错,返回常量值INADDR_NONE(这个值一般为一个32位均为1的值),这意味着点分二进制数串255.255.255.255(IPv4的有限广播地址)不能由此函数进行处理。

  inet_ntoa将一个32位的网络字节序二进制IPv4地址转换为相应的点分十进制数串。

  inet_aton 和inet_ntoa(线程不安全)现在用的比较多,推荐使用。

    static void bail(const char *on_what)

{

fputs(on_what,stderr);

fputs("\n",stderr);

}

int main(int argc,char **argv)

{

int z;

struct sockaddr_in adr_inet; /* AF_INET */

int len_inet; /* length */

int sck_inet; /* Socket */

/* Create a Socket */

sck_inet = socket(AF_INET, SOCK_STREAM, 0);

if (sck_inet == -1)

bail("Socket()");

/* Establish address */

memset(&adr_inet, 0, sizeof(adr_inet));

adr_inet.sin_family = AF_INET;

adr_inet.sin_port = htons(9000); .

if( !inet_aton("127.0.0.1", &adr_inet.sin_addr))/*******************

bail("bad address");

len_inet = sizeof(adr_inet);

/* Bind it to the socket */

z = bind(sck_inet, (struct sockaddr *)&adr_inet,len_inet);

if(z == -1)

bail("bind()");

/* Display our socket address */

system("netstat -pa --tcp 2>/dev/null" | grep inetaton");

return 0;

}

程序的运行结果如下:

S$ ./inetaton

tcp 0 0 127.0.0.23:9000 *:* CLOSE 1007/inetaton

 

  inet_pton和inet_ntop两个函数较新,对IPv4和IPv6地址都能进行处理,字母p代表presentation,字母n代表numeric。地址的表达格式通常是ASCII串,数值格式则是存在于套接口地址结构中的二进制值。

 

 

1 #include<arpa/inet.h>
2 
3 /* 若函数成功,则返回1;若输入不是有效的格式,则函数返回0;若处理失败,函数返回-1 */
4 int inet_pton(int family, const char *strptr, void *addrptr);
5 
6 /* 若函数处理成功,返回指向结果的指针;若函数处理失败,返回NULL */
7 const char* inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

 

  两个函数的参数family既可以是AF_INET,也可以是AF_INET6。如果以不被支持的地址族作为family参数,两个函数都返回错误,并将errno置为EAFNOSUPPORT。

  第一个函数转换由指针strptr所指的串,通过指针addrptr存储二进制结果,如果成功,则返回值为1;如果对于指定的family输入串不是有效的表达格式,则返回值为0.

  inet_ntop进行相反的转换,即从数值格式(addrptr)到表达格式(strptr)进行转换。参数len是目标的大小,以免函数溢出其调用者的缓冲区。为有助于规定这个大小,在头文件<netinet/in.h>中有如下定义:

  

1 #define INET_ADDRSTRLEN 16     /* for IPv4 dotted-decimal */
2 #define INET6_ADDRSTRLEN 46   /* for IPv6 hex string */

  如果len太小,无法容纳表达格式结果(包括终止的空字符),则返回一个空指针,并置errno为ENOSPC。

  函数inet_ntop的参数strptr可不能是个空指针,调用者必须为目标分配内存指定大小。成功时,此指针即函数的返回值。

---------------------------------------------------------------------------------------------

上面的这几个函数,都是在字符串和整数之间转换。

下面这几个函数用的也比较多,是整数之间的转换。

 

POSIX 提供了 4 个函数(也可能是用宏来实现的),可以让本机字节序和网络字节序之间进行互转。它们分别是:

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

其中,函数名字中的 h 表示 host(本机),n 表示 network(网络),而 l 表示要转换的数据是 4 字节,s 表示要转换的数据是 2 字节。

. 总结

  • in_addr_t 和 in_addr 的区别和联系
  • in_addr 是网络字节序的
  • in_addr_t 是什么字节序是不确定的
  • 掌握相关的转换函数
  • inet_addr 和 inet_aton 的区别
  • inet_addr 和 inet_network 的区别

 

 

 

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值