IP地址转换函数

文章详细介绍了在Unix网络编程中如何进行地址转换,包括主机字节序与网络字节序之间的转换函数htons,htonl,ntohs,ntohl的使用,以及点分十进制字符串与网络字节序之间的转换函数inet_addr,inet_aton,inet_network,inet_ntoa的应用。同时提到了较新的inet_pton和inet_ntop函数,它们支持IPv4和IPv6地址的转换。
摘要由CSDN通过智能技术生成

前言:

在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 字节。

转换函数

包含了字符串和整数之间转换整数之间的转换

  1. 点分十进制数串转网络字节序
/*
    函数原型
    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
  1. 点分十进制数串转主机字节序
ip_addr = inet_network("192.168.2.125");   
if(ip_addr==INADDR_NONE)               
printf("ERROR");
printf("inet_network:%d\n", ip_addr);         //主机字节序     
//-1062731139
  1. 主机字节序转网络字节序
int ip2_addr;
ip2_addr =htonl(ip_addr);
printf("ip2_addr:%d\n", ip2_addr);
  1. 网络字节序转主机字节序
ip_addr =ntohl(ip2_addr);
printf("ip_addr:%d\n", ip_addr);
  1. 点分十进制数串转网络字节序
 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地址都能进行处理

在这里我们就先放一个示例供参考:

  1. 点分十进制数串转网络字节序
    
	//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
  1. 网络字节序转点分十进制字符串
    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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值