zoukankan      html  css  js  c++  java
  • 识别有效的IP地址和掩码并进行分类统计

    淅淅沥沥地先积累一些知识:

    合法的子网掩码,按位取反,加一后,二进制位中,只有一个1。

    IP是32位二进制数据,通常以十进制表示,并以“.”分隔。IP地址是一种逻辑地地址,用来标识网络中一个个主机,IP有唯一性,即每台机器的IP在全世界是唯一的。

     电脑之间要实现网络通信,就必须要有一个合法的ip地址。IP地址=网络地址+主机地址,(又称:主机号和网络号组成)ip地址的结构使我们可以在Internet上很方便的寻址。ip地址通常用更直观的,以圆点分隔号的四个十进制数字表示,每个数字从0到255,如某一台主机的ip地址为:128.20.4.1在局域网里,同样也需要ip地址,一般内网的ip地址是以192.168开头的,这样很容易区分公网和内网的ip地址

    (收笔于此,暂去徜徉!2019-07-20 22:06:39)

    网段

    IP默认分配的子网掩码每段只有255或0

    A类的默认子网掩码 255.0.0.0 一个子网最多可以容纳1677万多台电脑(2^24-  )

    B类的默认子网掩码 255.255.0.0 一个子网最多可以容纳6万台电脑(2^16-  )

    C类的默认子网掩码 255.255.255.0 一个子网最多可以容纳254台电脑  (2^8-2)

    所有的子网掩码是由一串连续的1和一串连续的0组成的(一共4段,每段8位,一共32位数)

    详见:https://blog.csdn.net/jlminghui/article/details/50518765

    子网掩码决定的是一个子网的计算机数目,计算机公式是2的m次方,其中,我们可以把m看作后面0的个数。如255.255.255.0转换成二进制,那就是11111111.11111111.11111111.00000000,后面有8颗0,那m就是8,255.255.255.0这个子网掩码可以容纳2的8次方(台)电脑,也就是256台,但是有两个IP是不能用的,那就是最后一段不能为0和255,减去这两台,就是254台。

    255.255.254.0 是由23个1组成,也就是23位掩码。简单的说,由左往右数1,把十进制的IP换算成二制后,前23位1相同的情况下就属于同一个网段内的IP,24位后的1随意变化,属于同一网段。例中IP(A) 188.188.0.111,通过这个23位限制,可以看出的范围就是属于 188.188.0.0~188.188.1.255范围,只有在这个范围内,才属于同一个网段内IP。IP(B)同网段的IP范围是188.188.4.0~188.188.5.255的范围,显然不在IP(A)的范围内,所以IP(A)与IP(B)不是同一网段内IP。

    现在的IP暂时由四段数字组成(以后将扩充更改),常分为三类IP:

     A类:0.0.0.0到126.255.255.255

     B类:128.0.0.0到191.255.255.255

     C类:192.0.0.0到223.255.255.255

    子网掩码:

    在同一网段,要求网络标识相同,网络标识就是用IP的二进制与子网掩码的二进制数据作'与'运算(可用WINDOWS计算器算二进制),所以结果相同,表示在同一网段,而不是IP地址前几段相同就表示在同一网段。算网络标识的时候,A类IP只算第一段,B类只算第一,二段,C类IP算第一,二,三段。

     例:192.168.0.1 255.255.255.0的网络标识为:192.168.0.0

     192.168.0.1: 11000000.10101000.00000000.00000001

     255.255.255.0:11111111.11111111.11111111.00000000

     作与运算:

    11000000.10101000.00000000.00000000

     结果:192.168.0.0

     子网掩码决定了一个子网的计算机数目,简单的算法就是2的M次方。M表示二进制的子网掩码后面0的数目。

    如果第一个是255,则判断第二个是不是255,若第二个不是255,则第三个和第四个必须是0,同时第二个必须是254,252,248,240,224,192,128,0;若第二个为255,则第三个以此类推。

    如果第一个不是255,则同理,只能是254,252,248,240,224,192,128(注意不能为0),因为子网掩码mask可以以0开头,但不是有效的掩码。

    实例:一个公司有530台电脑,组成一个对等网,子网掩码如何设?IP如何设?

    子网掩码:

    2的M次方=530,求得M=10  (此处我尚有疑惑!     疑惑于黄昏得解:

    首先,无疑,530台电脑用B类IP最合适(A类不用说了,太多,C类又不够,肯定是B类),但是B类默认的子网掩码是255.255.0.0,可以容纳6万台电脑,显然不太合适,那子网掩码设多少合适呢?我们先来列个公式。
      2的m次方=560
       首先,我们确定2一定是大于8次方的,因为我们知道2的8次方是256,也就是C类IP的最大容纳电脑的数目,我们从9次方一个一个试2的9次方是 512,不到560,2的10次方是1024,看来2的10次方最合适了。
    )

     那么子网掩码最后为10个0,如此便是:11111111.11111111.11111100.00000000

     换成十进制便是:255.255.252.0

     再看IP,我们选一个B类IP,例如:188.188.×.×

     前两段按B类要随便设就可以,关键是第三段,只要网络标识相同就可以在同一网段就可以,我们先看网络标识:

     255.255.252.0:11111111.11111111.11111100.00000000

     188.188.×.×: 10111100.10111100.??????××.××××××××

     网络标识: 10111100.10111100.??????00.00000000

     上边×号无论填0和1结果都是0

     ?处填0和1都一样,我们就全填0,结果便是IP便是:

     10111100.10111100.000000××.××××××××,这个IP共有530台电脑,IP最后一段分给254台,一共要分530/254=2.086段,进一法则要分成3段,所以IP地址000000××处分成三个不同的数据即可,例:00000001,00000010,00000011,分别是1,2,3,这样IP地址就确定了188.188.1.×,188.188.2.×,188.188.3.×。

    拾锦:

    分配和计算子网掩码(Subnet mask)你会了吧,下面,我们来看看IP地址的网段。 

    相信好多人都和偶一样,认为IP只要前三段相同,就是在同一网段了,其实,不是这样的,同样,我样把IP的每一段转换为一个二进制数,这里就拿IP:192.168.0.1,子网掩码:255.255.255.0做实验吧。 
    192.168.0.1 
    11000000.10101000.00000000.00000001 
    (这里说明一下,和子网掩码一样,每段8位,不足8位的,前面加0补齐。) 
    IP    11000000.10101000.00000000.00000001 
    子网掩码  11111111.11111111.11111111.00000000 
    在这里,向大家说一下到底怎么样才算同一网段。 
    要想在同一网段,必需做到网络标识相同,那网络标识怎么算呢?各类IP的网络标识算法都是不一样的。A类的,只算第一段。B类,只算第一、二段。C类,算第一、二、三段。 
    算法只要把IP和子网掩码的每位数AND就可以了。 
    AND方法:0和1=0 0和0=0 1和1=1 
    如:And 192.168.0.1,255.255.255.0,先转换为二进制,然后AND每一位 
    IP      11000000.10101000.00000000.00000001 
    子网掩码    11111111.11111111.11111111.00000000 
    得出AND结果  11000000.10101000.00000000.00000000 
    转换为十进制192.168.0.0,这就是网络标识, 
    再将子网掩码反取,也就是00000000.00000000.00000000.11111111,与IP AND 
    得出结果00000000.00000000.00000000.00000001,转换为10进制,即0.0.0.1, 
    这0.0.0.1就是主机标识。要想在同一网段,必需做到网络标识一样。 

    我们再来看看这个改变默认子网掩码的B类IP 
    如IP:188.188.0.111,188.188.5.222,子网掩码都设为255.255.254.0,在同一网段吗? 
    先将这些转换成二进制 
    188.188.0.111 10111100.10111100.00000000.01101111 
    188.188.5.222 10111100.10111100.00000101.11011010 
    255.255.254.0 11111111.11111111.11111110.00000000 
    分别AND,得 
    10111100.10111100.00000000.00000000 
    10111100.10111100.00000100.00000000 
    网络标识不一样,即不在同一网段。 

    -------------------Reference:https://www.cnblogs.com/way_testlife/archive/2010/10/05/1844399.html

    The problem: https://www.nowcoder.com/practice/de538edd6f7e4bc3a5689723a7435682?tpId=37&tqId=21241&tPage=1&rp=&ru=/ta/huawei&qru=/ta/huawei/question-ranking

    在更进一步的探索前打下一些基础:

    关于string --->int的转换:

    1 #include<bits/stdc++.h>
    2 using namespace std;
    3 int main()
    4 {
    5     string a="123456";
    6     int c=atoi(a.c_str());
    7     cout<<c%100<<endl;
    8     return 0;
    9 }    //显示56.

    参考链接:https://www.cnblogs.com/skunk/archive/2009/05/06/1450903.html

    夏夜拾锦(我喜欢那种循序渐进水到渠成之感,加油冲呀!)

    255.255.255.255 为非法子网掩码(题目的意思,实际这个掩码,也能用)

    Analysis adventure:
    判断子网掩码是否有效

        通过判断是否为255.255.255.255 如果是的话,错误加一,继续下次循环

        判断别的子网掩码是否正确。根据子网掩码二进制规律(开头为连续的1,然后为0),我们将子网掩码按位取反,然后加一,得到的新二进制位,然后我们通过判断二进制中1的个数来判断是否为合法的子网掩码。(因为合法的子网掩码,按位取反,加一后,二进制位中,只有一个1)(这真的是很厉害的校验是否是正确的子网掩码的方法,对位运算的理解很深刻 学习了)

    codes piece:

    清风朗月正相伴,先介绍一下位运算的相关知识:

    First: 按位与(And) (&)运算  将参与运算的两操作数各自对应的二进制位进行与操作。

    intro: 将参与运算的两操作数各自对应的二进制位进行与操作。

    例如:6的二进制是110,11的二进制是1011,那么6 & 11的结果就是2   

     110                       
    &  1011
    ------------
       0010  -->  2        & 运算常常用来将某变量的某些位清0,而保留其它位不变。

    例如,需要将int型变量n的低8位全置成0,而其余位不变,则用:
           n = n & 0xFFFFFF00
    & 也常用于二进制取位操作,例如一个数 & 1的结果就是取二进制的最末位。如果要判断n的第8位(从右往左,从1开始数)是否是1,则用:
                 if (n & 0x80 == 0x80)  语句
    附注:int型是32个二进制位,16进制整数每个数字代表4个二进制位,故16进制int型常量最多是8位。(紫色是神秘之色,以寄未知浩渺)
    --------------------------------------------https://blog.csdn.net/c20180630/article/details/57076374

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
    	int a=3;//00000011
    	int b=5;//00000101
    	printf("%d",a&b);// it couts 1   3&5=1
    }
    

    A trick:

    用于消去x的最后一位1.

    x & (x-1)
    x = 1100
    x-1 = 1011
    x & (x-1) = 1000
    

      

      

    Second: 左移(<<)运算

     a << b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2

    (这样做要求保证高位的1不被移出)。
    通常认为a << 1比a * 2更快,因为前者是更底层一些的操作。因此程序中乘以2的操作请尽量用左移一位来代替。

    定义常量时可以用<<运算。你可以方便地用(1 << 16) - 1来表示65535。很多算法和数据结构要求数据规模必须是2的幂,此时可以用<<来定义MAXN等常量。

    Third: 右移(>>)运算

    a >> b表示二进制右移b位(去掉末b位)。
    当a是正整数时,a>>b等价于a/(2的b次方)
    当a是负整数时,a>>b并不等价与a/(2的b次方),而是等于a/(2的b次方)上取整。
    如a=-9
    cout<<a/2; //输出-4.
    cout<<(a>>1); //输出-5.

    那个子网掩码的判断函数如下:

    int validMask(char *p) {
    int flag,i ;
    unsigned int b1 = 0, n[4];
    sscanf(p, "%u.%u.%u.%u", &n[3], &n[2], &n[1], &n[0]);   //sscanf参见https://www.cnblogs.com/hejing-swust/p/7793958.html
    if(n[0] == 255 &&n[1] == 255 &&n[2] == 255 &&n[3] == 255 ) {
    flag = false;
    return flag;
    }
    for(i = 0; i < 4; ++i)
    b1 += n[i] << (i * 8);
    b1 = ~b1 + 1;      //很等待我去探索丫!
    if((b1 & (b1 - 1)) == 0) {
    flag = true;
    } else
    flag = false;
    return flag;
    }

    Here is my version:

     1 int validMask(char *p)
     2 {
     3     int flag,i;
     4     unsigned int b1=0,n[4];
     5     sscanf(p,"%u.%u.%u.%u",&n[3],&n[2],&n[1],&n[0]);
     6     if(n[0]==255 && n[1]==255 && n[2]==255 && n[3]==255){
     7         flag=false;
     8         return flag;
     9     }
    10     for(i=0;i<4;i++) b1+=n[i]<<(i*8);
    11     b1=~b1+1;
    12     if(b1 & (b1-1) ==0) flag=true;//判断二进制中1的个数来判断是否为合法的子网掩码
    13     else flag=false;
    14     return flag;
    15 }

    Then............

    我的借鉴的代码是这样的形式的:

     1 #include <stdio.h>
     2 #include <arpa/inet.h>
     3 #include <sys/socket.h>
     4 #include <netinet/in.h>
     5 #include <strings.h>
     6 #include <stdlib.h>
     7 #include <string.h>
     8 #define true 1
     9 #define false 0
    10 int validMask(char *p) {
    11 int flag,i ;
    12 unsigned int b1 = 0, n[4];
    13 sscanf(p, "%u.%u.%u.%u", &n[3], &n[2], &n[1], &n[0]);
    14 if(n[0] == 255 &&n[1] == 255 &&n[2] == 255 &&n[3] == 255 ) {
    15     flag = false;
    16     return flag;
    17 }
    18 for(i = 0; i < 4; ++i)
    19     b1 += n[i] << (i * 8);
    20 b1 = ~b1 + 1;
    21 if((b1 & (b1 - 1)) == 0) {
    22     flag = true;
    23 } else
    24     flag = false;
    25 return flag;
    26 }
    27 int main() {
    28 char str[50];
    29 int a =0, b = 0, c = 0, d = 0, e = 0, err = 0, pri = 0;
    30 while(fgets(str,50,stdin)) {
    31     char *tok = str;
    32     char p[2][20] = {0};
    33     int i = 0;
    34     while ((tok = strtok(tok, "~")) != NULL) {
    35         strcpy(p[i], tok);
    36         tok = NULL;
    37         i ++ ;
    38         if(i == 2)
    39             i = 0;
    40     }
    41     int flag = validMask(p[1]);
    42     if(flag) {
    43         struct in_addr s;
    44         unsigned int ip1,ip2;
    45         int valid = inet_pton(AF_INET,p[0],(void *)&s);
    46         sscanf(p[0],"%u.%u",&ip1,&ip2);
    47         if(valid) {
    48             if(ip1>=1 && ip1 <=126)
    49                 a++;
    50             else if(ip1>=128 && ip1 <=191)
    51                 b++;
    52             else if(ip1>=192 && ip1 <=223)
    53                 c++;
    54             else if(ip1>=224 && ip1 <=239)
    55                 d++;
    56             else if(ip1>=240 && ip1 <=255)
    57                 e++;
    58             if(ip1==10
    59                     || (ip1==172 && ip2 >=16 &&ip2 <=31)
    60                     || (ip1==192 && ip2 ==168))
    61                 pri ++;
    62         } else
    63             err ++;
    64     } else
    65         err++;
    66 }
    67 printf("%d %d %d %d %d %d %d
    ",a,b,c,d,e,err,pri);
    68 return 0;
    69 }

    有很多的细节来处理的,加油!一会儿我再来补述哦!

  • 相关阅读:
    mybatis源码追踪2——将结果集映射为map
    Mybatis的cache
    mybatis拦截器
    mybatis中单个参数的引用
    mybatis源码追踪1——Mapper方法用法解析
    win8 下 intellij idea 13 中文输入覆盖的问题
    firebug中html显示为灰色的原因总结
    extjs4.0以上添加多行工具栏的方法
    去除eclipse的validating
    An interview question from MicroStrategy
  • 原文地址:https://www.cnblogs.com/dragondragon/p/11219523.html
Copyright © 2011-2022 走看看