C++判断IP地址是否有效

判断是否为有效IP的方法

  1. 字符串验证 :比较麻烦,且容易考虑不全;
  2. 正则表达式: C++11之后支持;
  3. IP地址与网络传输数值转换: 高效,优于正则表达式;

正则表达式和网络数值转换的比较

#include <regex>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/time.h>
//#include <netinet/in.h>
using namespace std;

unsigned long long get_ms()
{
    struct timeval time_v = { 0 };
    gettimeofday(&time_v, NULL);
    return (unsigned long long)time_v.tv_sec * 1000 + time_v.tv_usec / 1000;
}

int main()
{
    string ip("199.199.199.199");
    regex check_ip("(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])[.](25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])[.](25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])[.](25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])");
    struct in_addr s;
    uint64_t start_time1 = get_ms();
    for (int i = 0; i < 10000; ++i) {
        if (1 > inet_pton(AF_INET, ip.c_str(), &s)) {
            printf("格式不正确\n");
        }
    }
    printf("inet_pton消耗时间 [%llu]\n", (get_ms() - start_time1));
    uint64_t start_time2 = get_ms();
    for (int i = 0; i < 10000; ++i) {
        if (!regex_match(ip, check_ip)) {
            printf("格式不正确\n");
        }
    }
    printf("regex_match消耗时间 [%llu]\n", (get_ms() - start_time2));

    return 0;
}

代码执行结果如下

jhj@makeenv:~/jared$ g++ -g -std=c++14 test.cpp -o test
jhj@makeenv:~/jared$ ./test 
inet_pton消耗时间 [1]
regex_match消耗时间 [76]

详细介绍网络数值转换

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
int main (void)
{
    char IPdotdec[20]; //存放点分十进制IP地址
    struct in_addr s; // IPv4地址结构体
    // 输入IP地址
    printf("Please input IP address: ");
    scanf("%s", IPdotdec);
    // 转换
    inet_pton(AF_INET, IPdotdec, (void *)&s);
    printf("inet_pton: 0x%x\n", s.s_addr); // 注意得到的字节序
    // 反转换
    inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);
    printf("inet_ntop: %s\n", IPdotdec);
    return 0;
}

代码执行结果如下

Please input IP address: 199.199.199.199
inet_pton: 0xc7c7c7c7
inet_ntop: 199.199.199.199
Please input IP address: 299.299.299.299
inet_pton: 0x0
inet_ntop: 0.0.0.0

inet_pton是一个IP地址转换函数,可以在将IP地址在“点分十进制”和“二进制整数”之间转换,而且inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6。算是比较新的函数了。

1.把ip地址转化为用于网络传输的二进制数值

int inet_aton(const char *cp, struct in_addr inp);
inet_aton() 转换网络主机地址ip(如192.168.1.10)为二进制数值,并存储在struct in_addr结构中,即第二个参数
inp,函数返回非0表示cp主机有地有效,返回0表示主机地址无效。(这个转换完后不能用于网络传输,还需要调用htons或htonl函数才能将主机字节顺序转化为网络字节顺序)

in_addr_t inet_addr(const char *cp);
inet_addr函数转换网络主机地址(如192.168.1.10)为网络字节序二进制值,如果参数char *cp无效,函数返回-1(INADDR_NONE),这个函数在处理地址为255.255.255.255时也返回-1,255.255.255.255是一个有效的地址,不过inet_addr无法处理;

2.将网络传输的二进制数值转化为成点分十进制的ip地址

char *inet_ntoa(struct in_addr in);
inet_ntoa 函数转换网络字节排序的地址为标准的ASCII以点分开的地址,该函数返回指向点分开的字符串地址(如192.168.1.10)的指针,该字符串的空间为静态分配的,这意味着在第二次调用该函数时,上一次调用将会被重写(复盖),所以如果需要保存该串最后复制出来自己管理!

我们如何输出一个点分十进制的IP呢?我们来看看下面的程序:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int main()
{
 struct in_addr addr1,addr2;
 ulong l1,l2;
 l1= inet_addr("192.168.0.74");
 l2 = inet_addr("211.100.21.179");
 memcpy(&addr1, &l1, 4);
 memcpy(&addr2, &l2, 4);
 printf("%s : %s\n", inet_ntoa(addr1), inet_ntoa(addr2)); //注意这一句的运行结果
 printf("%s\n", inet_ntoa(addr1));
 printf("%s\n", inet_ntoa(addr2));
 return 0;
}

实际运行结果如下:

192.168.0.74 : 192.168.0.74          //从这里可以看出,printf里的inet_ntoa只运行了一次。  
192.168.0.74  
211.100.21.179  

inet_ntoa返回一个char *,而这个char *的空间是在inet_ntoa里面静态分配的,所以inet_ntoa后面的调用会覆盖上一次的调用。第一句printf的结果只能说明在printf里面的可变参数的求值是从右到左的,仅此而已。

3.新型网路地址转化函数inet_pton和inet_ntop

这两个函数是随IPv6出现的函数,对于IPv4地址和IPv6地址都适用,函数中p和n分别代表表达(presentation)和数值(numeric)。地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构的二进制值。

#include <arpe/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr); //将点分十进制的ip地址转化为用于网络传输的数值格式
返回值:若成功则为1,若输入不是有效的表达式则为0,若出错则为-1

const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len); //将数值格式转化为点分十进制的ip地址格式
返回值:若成功则为指向结构的指针,若出错则为NULL

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

(2)第一个函数尝试转换由strptr指针所指向的字符串,并通过addrptr指针存放二进制结果,若成功则返回值为1,否则如果所指定的family而言输入字符串不是有效的表达式格式,那么返回值为0.

(3)inet_ntop进行相反的转换,从数值格式(addrptr)转换到表达式(strptr)。inet_ntop函数的strptr参数不可以是一个空指针。调用者必须为目标存储单元分配内存并指定其大小,调用成功时,这个指针就是该函数的返回值。len参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区。如果len太小,不足以容纳表达式结果,那么返回一个空指针,并置为errno为ENOSPC。

4.示例

inet_pton(AF_INET, ip, &foo.sin_addr);  // 代替 foo.sin_addr.addr=inet_addr(ip);
 
char str[INET_ADDRSTRLEN];
char *ptr = inet_ntop(AF_INET,&foo.sin_addr, str, sizeof(str));   // 代替 ptr = inet_ntoa(foo.sin_addr)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值