前言:
在Unix网络编程中,我们常用到地址转换函数,它将ASCII字符串(如"206.62.226.33")与网络字节序的二进制值(这个值保存在套接口地址结构中)间进行地址的转换。当然也包含主机字节序与网络字节序的转换
结构体熟悉
struct in_addr {
uint32_t s_addr; // ip地址的网络字节序
};
上述结构体为struct sockaddr_in 中的参数3
struct sockaddr_in {
sa_family_t sin_family; // 地址簇
in_port_t sin_port; // 端口的网络字节序
struct in_addr sin_addr; // internet address
};
概念熟悉
POSIX 提供了 4 个函数(也可能是用宏来实现的),可以让本机字节序和网络字节序之间进行互转,是整数之间的转换。它们分别是
#include <arpa/inet.h>
函数返回值是一个32位的网络字节顺序;
函数的作用是将一个32位数从主机字节顺序转换成网络字节顺序
uint32_t htonl(uint32_t hostlong);
函数返回值是一个16位的网络字节顺序;
函数的作用是将一个16位数从主机字节顺序转换成网络字节顺序,简单的说就是把一个16位数高低位呼唤。
uint16_t htons(uint16_t hostshort);
函数返回值是一个32位的主机字节顺序;
函数的作用是将一个32位数由网络字节顺序转换为主机字节顺序。
uint32_t ntohl(uint32_t netlong);
函数返回值是一个16位的主机字节顺序;
函数的作用是将一个16位数由网络字节顺序转换为主机字节顺序,简单的说就是把一个16位数高低位互换。
uint16_t ntohs(uint16_t netshort);
其中,函数名字中的 h 表示 host(本机),n 表示 network(网络),而 l 表示要转换的数据是 4 字节,s 表示要转换的数据是 2 字节。
转换函数
包含了字符串和整数之间转换与整数之间的转换
- 点分十进制数串转网络字节序
/*
函数原型
char* inet_ntoa(struct in_addr inaddr);
in_addr_t inet_addr(const char *strptr);
*/
int ip_addr;
ip_addr = inet_addr("192.168.2.125"); //设置ip点分十进制地址的地址
if(ip_addr==INADDR_NONE) // 返回值错误判断
printf("ERROR");
printf("inet_addr:%d\n", ip_addr); //打印转换后的网络字节序
//2097326272
- 点分十进制数串转主机字节序
ip_addr = inet_network("192.168.2.125");
if(ip_addr==INADDR_NONE)
printf("ERROR");
printf("inet_network:%d\n", ip_addr); //主机字节序
//-1062731139
- 主机字节序转网络字节序
int ip2_addr;
ip2_addr =htonl(ip_addr);
printf("ip2_addr:%d\n", ip2_addr);
- 网络字节序转主机字节序
ip_addr =ntohl(ip2_addr);
printf("ip_addr:%d\n", ip_addr);
- 点分十进制数串转网络字节序
struct in_addr inet_ip_addr;
ip_addr = inet_aton("192.168.2.125", &inet_ip_addr);//inet_aton将strptr所指的C字符转换为32位网络字节序二进制值,并用一个出参addrptr来存储,返回值为1代表成功,否则返回0。
printf("%d\n",inet_ip_addr.s_addr);
//2097326272
6 . 网络字节序转点分十进制字符串
struct in_addr network;
network.s_addr=2097326272; //为s_addr赋值--网络字节序
printf("IP : %s\n", inet_ntoa(network));
//IP : 192.168.2.125
inet_pton和inet_ntop两个函数较新,对IPv4和IPv6地址都能进行处理
在这里我们就先放一个示例供参考:
- 点分十进制数串转网络字节序
//int inet_pton(int family, const char *strptr, void *addrptr);//若函数成功,则返回1;若输入不是有效的格式,则函数返回0;若处理失败,函数返回-1
int ret;
struct in_addr var_ip;
ret = inet_pton(AF_INET, "192.168.2.125", (void *)&var_ip);
if(ret==0)
printf("IP is not contained in address family\n");
if(ret == -1)
printf("errno: EAFNOSUPPORT\n");
printf("inet_pton:%d\n",var_ip.s_addr);
//2097326272
- 网络字节序转点分十进制字符串
char ip_buff[INET_ADDRSTRLEN]={0};
struct in_addr net_ip;
net_ip.s_addr = 2097326272;
const char *ret1;
ret1 = inet_ntop(AF_INET, (const void *)&net_ip.s_addr, ip_buff, sizeof(ip_buff) );
if(ret1==NULL){ // 对返回值进行错误判断
if(strcmp(ret1,"EAFNOSUPPORT"))
perror("AF error:");
if(strcmp(ret1,"ENOSPC"))
printf("address string over setted size");
} // 会报警告
printf("ip_buff:%s\n", ip_buff);
//ip_buff:192.168.2.125
区别
我们看到inet_addr与inet_aton都可以用于点分十进制数串转网络字节序,inet_addr与inet_aton不同在于,他的返回值为转换后的32位网络字节序二进制值,而不是作为出参返回,这样存在一个问题,他的返回值返回的有效IP地址为0.0.0.0到255.255.255.255,如果函数出错,返回常量值INADDR_NONE(这个值一般为一个32位均为1的值),这意味着点分二进制数串255.255.255.255(IPv4的有限广播地址)不能由此函数进行处理。
整体源码:可以直接编译执行
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netinet/in.h>
void main()
{
struct sockaddr_in add;
add.sin_addr.s_addr = inet_addr("192.168.1.1"); //构建网络地址,inet_addr()将一个点分十进制的IPv4转换成一个长整数型数
printf("------add.sin_addr.s_addr:%d-------\n",add.sin_addr.s_addr);
printf("------add.sin_addr:%d-------\n",add.sin_addr);
printf("ip is %s\n",inet_ntoa(add.sin_addr)); //将一个in_addr结构体对象转换成一个用"."表示的IP字符串的形式,比如将:in(in_addr) -> "192.168.1.10"或者inet_ntoa将一个32位的网络字节序二进制IPv4地址转换为相应的点分十进制数串。
//点分十进制数串转网络字节序
int ip_addr;
ip_addr = inet_addr("192.168.2.125"); //设置ip点分十进制地址的地址
if(ip_addr==INADDR_NONE) // 返回值错误判断
printf("ERROR");
printf("inet_addr:%d\n", ip_addr); //打印转换后的网络字节序
//2097326272
//点分十进制数串转主机字节序
ip_addr = inet_network("192.168.2.125");
if(ip_addr==INADDR_NONE)
printf("ERROR");
printf("inet_network:%d\n", ip_addr); //主机字节序
//-1062731139
//主机字节序转网络字节序
int ip2_addr;
ip2_addr =htonl(ip_addr);
printf("ip2_addr:%d\n", ip2_addr);
//网络字节序转主机字节序
ip_addr =ntohl(ip2_addr);
printf("ip_addr:%d\n", ip_addr);
//点分十进制数串转网络字节序
struct in_addr inet_ip_addr;
ip_addr = inet_aton("192.168.2.125", &inet_ip_addr);//inet_aton将strptr所指的C字符转换为32位网络字节序二进制值,并用一个出参addrptr来存储,返回值为1代表成功,否则返回0。
printf("%d\n",inet_ip_addr.s_addr);
//2097326272
//网络字节序转点分十进制字符串
struct in_addr network;
network.s_addr=2097326272; //为s_addr赋值--网络字节序
printf("IP : %s\n", inet_ntoa(network));
//IP : 192.168.2.125
//点分十进制数串转网络字节序
int ret;
struct in_addr var_ip;
ret = inet_pton(AF_INET, "192.168.2.125", (void *)&var_ip);
if(ret==0)
printf("IP is not contained in address family\n");
if(ret == -1)
printf("errno: EAFNOSUPPORT\n");
printf("inet_pton:%d\n",var_ip.s_addr);
//2097326272
//网络字节序转点分十进制字符串
char ip_buff[INET_ADDRSTRLEN]={0};
struct in_addr net_ip;
net_ip.s_addr = 2097326272;
const char *ret1;
ret1 = inet_ntop(AF_INET, (const void *)&net_ip.s_addr, ip_buff, sizeof(ip_buff) );
if(ret1==NULL){ // 对返回值进行错误判断
if(strcmp(ret1,"EAFNOSUPPORT"))
perror("AF error:");
if(strcmp(ret1,"ENOSPC"))
printf("address string over setted size");
} // 会报警告
printf("ip_buff:%s\n", ip_buff);
}