Linux c语言判断一个字符串 ipv4地址是内网ip还是外网ip

一、内网ip简介

内网IP地址是指在局域网中使用的IP地址,不同于公网IP地址,不向互联网开放,只在局域网内有效。内网IP地址通常由路由器或交换机等网络设备动态分配或静态分配,用于局域网内的设备互相通信,不需要向外部网络公开。

在IPv4地址中,有三个私有地址段专门用于内网IP地址,它们是:

10.0.0.010.255.255.25510.0.0.0/8172.16.0.0172.31.255.255172.16.0.0/12192.168.0.0192.168.255.255192.168.0.0/16

特殊的内网ip地址:

169.254.0.0169.254.255.255 

169.254.0.0 到 169.254.255.255 之间的地址是一个特殊的保留地址范围,也称为APIPA地址(Automatic Private IP Addressing)。APIPA地址是一种用于自动分配IP地址的机制,通常用于在缺乏DHCP服务器的情况下,允许设备自动配置自己的IP地址。

二、特殊IP地址

如下所示:
(1)通配符地址
(2)环回地址
(3)D/E类地址

  0.0.0.0					 // 通配符地址
127.0.0.0 - 127.255.255.255  // 本地环回地址
224.0.0.0 - 255.255.255.255  // D/E class 地址

三、代码示例

3.1 代码测试

#include <iostream>
#include <string>
#include <vector>

#include <arpa/inet.h>

//检查字符串IP是否合法
//如果合法,获取该字符串IP的:host  byte order
bool _is_check_ip_true(const std::string& string_ip, uint32_t& host_num)
{
    struct in_addr addr;   // IPv4地址结构体
  
    if (inet_pton(AF_INET, string_ip.c_str(), &addr) != 1) {
        return false;
    } 

   host_num = ntohl(addr.s_addr);

    return true;

}

//判断是否是内网ip
bool isInternalIP(uint32_t& host_num) {

    if ((host_num >= ntohl(inet_addr("10.0.0.0"))) && (host_num <= ntohl(inet_addr("10.255.255.255")))) {
        return true;
    }else if ((host_num >= ntohl(inet_addr("172.16.0.0"))) && (host_num <= ntohl(inet_addr("172.31.255.255")))) {
        return true;
    }else if ((host_num >= ntohl(inet_addr("192.168.0.0"))) && (host_num <= ntohl(inet_addr("192.168.255.255")))) {
        return true;
    }else if ((host_num >= ntohl(inet_addr("169.254.0.0"))) && (host_num <= ntohl(inet_addr("169.254.255.255")))) {
        return true;
    }
    return false;
}

//过滤掉一些特殊的ip地址
bool FilterIP(uint32_t& host_num) {

    if ((host_num == ntohl(inet_addr("0.0.0.0")))) {
        return true;
    }else if ((host_num >= ntohl(inet_addr("127.0.0.0"))) && (host_num <= ntohl(inet_addr("127.255.255.255")))) {
        return true;
    }else if ((host_num >= ntohl(inet_addr("224.0.0.0"))) && (host_num <= ntohl(inet_addr("255.255.255.255")))) {
        return true;
    }
   
    return false;
}

int main()
{
    std::string ip;
    uint32_t host_num = 0;
    bool ret = false;

    while(1){
        
        std::cout << "Please enter an IP address: ";
        std::getline(std::cin, ip);

        if(ip.empty()){
            std::cout << "IP string is empty" << std::endl;
            continue;            
        }
        
        if("quit" == ip){
            break;
        }

        ret = _is_check_ip_true(ip.c_str(), host_num);
        if(!ret){
            std::cout << "IP addresses is not vaild: " << ip <<std::endl;
            continue;
        }
    
        ret = FilterIP(host_num);
        if(ret){
            std::cout << "Filtered IP addresses: " << ip <<std::endl;
            continue;
        }

        ret = isInternalIP(host_num);
        if(ret){
            std::cout << " IP isInternalIP:" << ip <<std::endl;
            continue;
        }    

        std::cout << "IP isOutternalIP:" << ip <<std::endl;

    }


    return 0;
}
# g++ test.cpp 
# ./a.out 
Please enter an IP address: 1.1.1.1
IP isOutternalIP: 1.1.1.1
Please enter an IP address: 0.0.0.0
Filtered IP addresses: 0.0.0.0
Please enter an IP address: 10.0.0.0
 IP isInternalIP: 10.0.0.0
Please enter an IP address: 125.1.1.10 
IP isOutternalIP: 125.1.1.10
Please enter an IP address: 2.2.2.2.2
IP addresses is not vaild: 2.2.2.2.2
Please enter an IP address: quit

3.2 函数说明

3.2.1 inet_pton函数

(1)

NAME
       inet_pton - convert IPv4 and IPv6 addresses from text to binary form

SYNOPSIS
       #include <arpa/inet.h>

       int inet_pton(int af, const char *src, void *dst);

DESCRIPTION
       This function converts the character string src into a network address structure in the af address family, then copies the network address structure to dst.  The af
       argument must be either AF_INET or AF_INET6.

inet_pton函数是一个用于将一个IPv4或IPv6地址的点分十进制字符串转换为一个网络字节序二进制值的函数。它可以在IPv4和IPv6之间进行自适应转换。

该函数可以用来判断一个字符串ip格式是否正确。

一个简单的测试代码:

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    const char *ipaddr_str = "192.168.1.1";
    struct in_addr ipaddr;
    if (inet_pton(AF_INET, ipaddr_str, &ipaddr) <= 0) {
        printf("无效的IPv4地址字符串\n");
    } else {
        printf("转换后的IPv4地址为:%s\n", inet_ntoa(ipaddr));
    }
    return 0;
}

在Linux系统的C编程中,struct in_addr是一个用于表示IPv4地址的结构体类型,它定义在<netinet/in.h>头文件中。其定义如下:

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };

其中,in_addr_t类型是一个无符号32位整数类型,用于存储IPv4地址的二进制形式。而struct in_addr结构体则包含一个in_addr_t类型的成员s_addr,用于存储IPv4地址的二进制形式。

需要注意的是,struct in_addr结构体和in_addr_t类型都使用网络字节序(大端字节序)来表示IPv4地址,因此在使用struct in_addr结构体中的成员变量s_addr时,需要使用类似于htonl和ntohl这样的函数进行字节序转换,以确保正确地表示和处理IPv4地址。

(2)
其中inet_ntoa函数:

/* Convert Internet number in IN to ASCII representation.  The return value
   is a pointer to an internal array containing the string.  */
char *inet_ntoa(struct in_addr in);

inet_ntoa函数用于将一个IPv4地址的网络字节序二进制值转换为一个点分十进制字符串表示。该函数的返回值是一个指向缓冲区的指针,其中包含了转换后的点分十进制字符串表示。

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    uint32_t uint_host = 0xC0A80101;

    struct in_addr in;
    in.s_addr = htonl(uint_host);

    printf("转换前的IPv4地址主机字节序为:%08X\n", uint_host);
    printf("转换前的IPv4地址网络字节序为:%08X\n", in.s_addr);
    printf("转换后的IPv4地址点分十进制字符串为:%s\n", inet_ntoa(in));
    return 0;
}
$ ./a.out 
转换前的IPv4地址主机字节序为:C0A80101
转换前的IPv4地址网络字节序为:0101A8C0
转换后的IPv4地址点分十进制字符串为:192.168.1.1

与之相同功能的还有inet_ntop函数。

NAME
       inet_ntop - convert IPv4 and IPv6 addresses from binary to text form

SYNOPSIS
       #include <arpa/inet.h>

       const char *inet_ntop(int af, const void *src,
                             char *dst, socklen_t size);

DESCRIPTION
       This  function converts the network address structure src in the af address family into a character string.  The resulting string is copied to the buffer pointed to
       by dst, which must be a non-NULL pointer.  The caller specifies the number of bytes available in this buffer in the argument size.

       inet_ntop() extends the inet_ntoa(3) function to support multiple address families, inet_ntoa(3) is now considered to be deprecated in favor  of  inet_ntop().   The
       following address families are currently supported:

       AF_INET
              src  points  to  a struct in_addr (in network byte order) which is converted to an IPv4 network address in the dotted-decimal format, "ddd.ddd.ddd.ddd".  The
              buffer dst must be at least INET_ADDRSTRLEN bytes long.

       AF_INET6
              src points to a struct in6_addr (in network byte order) which is converted to a representation of this address in the most appropriate IPv6  network  address
              format for this address.  The buffer dst must be at least INET6_ADDRSTRLEN bytes long.

inet_ntoa函数和inet_ntop函数,这两个函数将网络字节序的32位整数转换为点分十进制字符串。

其中,inet_ntoa函数的返回值是一个指向缓冲区的指针,其中包含了转换后的点分十进制字符串表示。但是,由于inet_ntoa函数在内部使用一个静态缓冲区,因此不能保证线程安全,而且每次调用此函数时,它都会返回一个指向同一静态缓冲区的指针,因此在多个线程中同时使用此函数可能会导致竞争条件。

相比之下,inet_ntop函数则更加灵活,它可以将转换结果存储到指定的缓冲区中,并指定缓冲区的大小。这样可以避免由于使用静态缓冲区而导致的线程安全问题。因此,建议使用inet_ntop函数进行转换操作。

#include <stdio.h>
#include <arpa/inet.h>

int main() {

    uint32_t uint_host = 0xC0A80101;

    struct in_addr in;
    in.s_addr = htonl(uint_host);

    char buf[INET_ADDRSTRLEN];
    const char *ipaddr_str = inet_ntop(AF_INET, &in, buf, INET_ADDRSTRLEN);
    if (ipaddr_str == NULL) {
        printf("转换失败\n");
    } else {
        printf("转换前的IPv4地址主机字节序为:%08X\n", uint_host);
        printf("转换前的IPv4地址网络字节序为:%08X\n", in.s_addr);
        printf("转换后的IPv4地址点分十进制字符串为:%s\n", ipaddr_str);
    }
    return 0;
}
$ ./a.out 
转换前的IPv4地址主机字节序为:C0A80101
转换前的IPv4地址网络字节序为:0101A8C0
转换后的IPv4地址点分十进制字符串为:192.168.1.1

3.2.2 ntohl函数

ntohl函数用于将一个32位无符号整数(从网络字节序(大端字节序)转换为主机字节序(小端字节序)。该函数返回转换后的32位无符号整数。

uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__));
#include <stdio.h>
#include <arpa/inet.h>

int main() {
    uint32_t netlong = 0x0101A8C0;
    uint32_t hostlong = ntohl(netlong);
    printf("网络字节序的32位整数为:%08X\n", netlong);
    printf("主机字节序的32位整数为:%08X\n", hostlong);
    return 0;
}
$ ./a.out 
网络字节序的32位整数为:0101A8C0
主机字节序的32位整数为:C0A80101

3.2.3 inet_addr函数

/* Convert Internet host address from numbers-and-dots notation in CP
   into binary data in network byte order.  */
in_addr_t inet_addr (const char *__cp) __THROW;

inet_addr函数用于将一个IPv4地址的点分十进制字符串转换为一个网络字节序的32位整数。

其中,cp参数是一个指向点分十进制字符串的指针,表示要转换的IPv4地址。返回值是一个网络字节序的32位整数,表示转换后的IPv4地址。

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    const char *ipaddr_str = "192.168.1.1";
    in_addr_t ipaddr = inet_addr(ipaddr_str);
    if (ipaddr == INADDR_NONE) {
        printf("无效的IPv4地址字符串\n");
    } else {
        printf("转换后的IPv4地址为:%08X\n", ipaddr);
    }
    return 0;
}

在这个示例中,我们将点分十进制字符串"192.168.1.1"转换为一个网络字节序的32位整数。

$ ./a.out 
转换后的IPv4地址网络字节序为:0101A8C0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值