首页 > 技术文章 > 如何判断两个IP大小关系及是否在同一个网段中

slive 2013-09-02 12:58 原文

功能点
  • 判断某个IP地址是否合法

  • 判断两个IP地址是否在同一个网段中

  • 判断两个IP地址的大小关系

知识准备
基本原理
 
IP地址范围
0.0.0.0~255.255.255.255,包括了mask地址。
IP地址划分
  • A类地址:1.0.0.1~126.255.255.254

  • B类地址:128.0.0.1~191.255.255.254

  • C类地址:192.168.0.0~192.168.255.255

  • D类地址:224.0.0.1239.255.255.254

  • E类地址:240.0.0.1255.255.255.254

判断两个IP地址是否是同一个网段中
    要判断两个IP地址是不是在同一个网段,就将它们的IP地址分别与子网掩码做与运算,得到的结果一网络号,如果网络号相同,就在同一子网,否则,不在同一子网。

    例:假定选择了子网掩码255.255.254.0,现在分别将上述两个IP地址分别与掩码做与运算,如下图所示:

211.95.165.24 11010011 01011111 10100101 00011000
255.255.254.0 11111111 11111111 111111110 00000000
与的结果是: 11010011 01011111 10100100 00000000
211.95.164.78 11010011 01011111 10100100 01001110
255.255.254.0 11111111 11111111 111111110 00000000
与的结果是: 11010011 01011111 10100100 00000000
    可以看出,得到的结果(这个结果就是网络地址)都是一样的,因此可以判断这两个IP地址在同一个子网。

    如果没有进行子网划分,A类网络的子网掩码为255.0.0.0,B类网络的子网掩码为255.255.0.0,C类网络的子网掩码为255.255.255.0,缺省情况子网掩码为255.255.255.0

实现
  以Java语言实现,主要针对IPv4地址。

代码实现如下(包括注释):

  1 package org.slive.net;
  2 
  3 import java.net.UnknownHostException;
  4 import java.util.regex.Pattern;
  5 
  6 /**
  7 * <pre>
  8 * IP地址范围:
  9 * 0.0.0.0~255.255.255.255,包括了mask地址。
 10 *
 11 * IP地址划分:
 12 * A类地址:1.0.0.1~126.255.255.254
 13 * B类地址:128.0.0.1~191.255.255.254
 14 * C类地址:192.168.0.0~192.168.255.255
 15 * D类地址:224.0.0.1~239.255.255.254
 16 * E类地址:240.0.0.1~255.255.255.254
 17 *
 18 * 如何判断两个IP地址是否是同一个网段中:
 19 * 要判断两个IP地址是不是在同一个网段,就将它们的IP地址分别与子网掩码做与运算,得到的结果一网络号,如果网络号相同,就在同一子网,否则,不在同一子网。
 20 * 例:假定选择了子网掩码255.255.254.0,现在分别将上述两个IP地址分别与掩码做与运算,如下图所示:
 21 * 211.95.165.24 11010011 01011111 10100101 00011000
 22 * 255.255.254.0 11111111 11111111 111111110 00000000
 23 * 与的结果是: 11010011 01011111 10100100 00000000
 24 *
 25 * 211.95.164.78 11010011 01011111 10100100 01001110
 26 * 255.255.254.0 11111111 11111111 111111110 00000000
 27 * 与的结果是: 11010011 01011111 10100100 00000000
 28 * 可以看出,得到的结果(这个结果就是网络地址)都是一样的,因此可以判断这两个IP地址在同一个子网。
 29 *
 30 * 如果没有进行子网划分,A类网络的子网掩码为255.0.0.0,B类网络的子网掩码为255.255.0.0,C类网络的子网掩码为255.255.255.0,缺省情况子网掩码为255.255.255.0
 31 *
 32 * @author Slive
 33 */
 34 public class IpV4Util
 35 {
 36      // IpV4的正则表达式,用于判断IpV4地址是否合法
 37      private static final String IPV4_REGEX = "((\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})";
 38     
 39      // 系统子网掩码,它与ip组成一个地址
 40      private int mask;
 41     
 42      // 1代表A类,2代表B类,3代表C类;4代表其它类型
 43      public final static int IP_A_TYPE = 1;
 44      public final static int IP_B_TYPE = 2;
 45      public final static int IP_C_TYPE = 3;
 46      public final static int IP_OTHER_TYPE = 4;
 47     
 48      // A类地址范围:1.0.0.1---126.255.255.254
 49      private static int[] IpATypeRange;
 50      // B类地址范围:128.0.0.1---191.255.255.254
 51      private static int[] IpBTypeRange;
 52      // C类地址范围:192.168.0.0~192.168.255.255
 53      private static int[] IpCTypeRange;
 54     
 55      // A,B,C类地址的默认mask
 56      private static int DefaultIpAMask;
 57      private static int DefaultIpBMask;
 58      private static int DefaultIpCMask;
 59     
 60      // 初始化
 61      static
 62      {
 63           IpATypeRange = new int[2];
 64           IpATypeRange[0] = getIpV4Value("1.0.0.1");
 65           IpATypeRange[1] = getIpV4Value("126.255.255.254");
 66          
 67           IpBTypeRange = new int[2];
 68           IpBTypeRange[0] = getIpV4Value("128.0.0.1");
 69           IpBTypeRange[1] = getIpV4Value("191.255.255.254");
 70          
 71           IpCTypeRange = new int[2];
 72           IpCTypeRange[0] = getIpV4Value("192.168.0.0");
 73           IpCTypeRange[1] = getIpV4Value("192.168.255.255");
 74          
 75           DefaultIpAMask = getIpV4Value("255.0.0.0");
 76           DefaultIpBMask = getIpV4Value("255.255.0.0");
 77           DefaultIpCMask = getIpV4Value("255.255.255.0");
 78      }
 79     
 80      /**
 81      * 默认255.255.255.0
 82      */
 83      public IpV4Util()
 84      {
 85           mask = getIpV4Value("255.255.255.0");
 86      }
 87     
 88      /**
 89      * @param mask 任意的如"255.255.254.0"等格式,如果格式不合法,抛出UnknownError异常错误
 90      */
 91      public IpV4Util(String masks)
 92      {
 93           mask = getIpV4Value(masks);
 94           if(mask == 0)
 95           {
 96                throw new UnknownError();
 97           }
 98      }
 99     
100      public int getMask()
101      {
102           return mask;
103      }
104     
105      /**
106      * 比较两个ip地址是否在同一个网段中,如果两个都是合法地址,两个都是非法地址时,可以正常比较;
107      * 如果有其一不是合法地址则返回false;
108      * 注意此处的ip地址指的是如“192.168.1.1”地址,并不包括mask
109      * @return
110      */
111      public boolean checkSameSegment(String ip1,String ip2)
112      {
113           return checkSameSegment(ip1,ip2,mask);
114      }
115     
116      /**
117      * 比较两个ip地址是否在同一个网段中,如果两个都是合法地址,两个都是非法地址时,可以正常比较;
118      * 如果有其一不是合法地址则返回false;
119      * 注意此处的ip地址指的是如“192.168.1.1”地址
120      * @return
121      */
122      public static boolean checkSameSegment(String ip1,String ip2, int mask)
123      {
124           // 判断IPV4是否合法
125           if(!ipV4Validate(ip1))
126           {
127                return false;
128           }
129           if(!ipV4Validate(ip2))
130           {
131                return false;
132           }
133           int ipValue1 = getIpV4Value(ip1);
134           int ipValue2 = getIpV4Value(ip2);
135           return (mask & ipValue1) == (mask & ipValue2);
136      }
137     
138      /**
139      * 比较两个ip地址是否在同一个网段中,如果两个都是合法地址,两个都是非法地址时,可以正常比较;
140      * 如果有其一不是合法地址则返回false;
141      * 注意此处的ip地址指的是如“192.168.1.1”地址
142      * @return
143      */
144      public static boolean checkSameSegmentByDefault(String ip1,String ip2)
145      {
146           int mask = getDefaultMaskValue(ip1);     // 获取默认的Mask
147           return checkSameSegment(ip1,ip2,mask);
148      }
149     
150      /**
151      * 获取ip值与mask值与的结果
152      * @param ipV4
153      * @return  32bit值
154      */
155      public int getSegmentValue(String ipV4)
156      {
157           int ipValue = getIpV4Value(ipV4);
158           return (mask & ipValue);
159      }
160     
161      /**
162      * 获取ip值与mask值与的结果
163      * @param ipV4
164      * @return  32bit值
165      */
166      public static int getSegmentValue(String ip, int mask)
167      {
168           int ipValue = getIpV4Value(ip);
169           return (mask & ipValue);
170      }
171     
172      /**
173      * 判断ipV4或者mask地址是否合法,通过正则表达式方式进行判断
174      * @param ipv4
175      */
176     public static boolean ipV4Validate(String ipv4)
177     {
178          return ipv4Validate(ipv4,IPV4_REGEX);
179     }
180    
181     private static boolean ipv4Validate(String addr,String regex)
182     {
183           if(addr == null)
184           {
185               return false;
186          }
187          else
188          {
189               return Pattern.matches(regex, addr.trim());
190          }
191      }
192    
193      /**
194      * 比较两个ip地址,如果两个都是合法地址,则1代表ip1大于ip2,-1代表ip1小于ip2,0代表相等;
195      * 如果有其一不是合法地址,如ip2不是合法地址,则ip1大于ip2,返回1,反之返回-1;两个都是非法地址时,则返回0;
196      * 注意此处的ip地址指的是如“192.168.1.1”地址,并不包括mask
197      * @return
198      */
199      public static int compareIpV4s(String ip1,String ip2)
200      {
201           int result = 0;
202           int ipValue1 = getIpV4Value(ip1);     // 获取ip1的32bit值
203           int ipValue2 = getIpV4Value(ip2); // 获取ip2的32bit值
204           if(ipValue1 > ipValue2)
205           {
206                result =  -1;
207           }
208           else if(ipValue1 <= ipValue2)
209           {
210                result = 1;
211           }
212           return result;
213      }
214     
215      /**
216      * 检测ipV4 的类型,包括A类,B类,C类,其它(C,D和广播)类等
217      * @param ipV4
218      * @return     返回1代表A类,返回2代表B类,返回3代表C类;返回4代表D类
219      */
220      public static int checkIpV4Type(String ipV4)
221      {
222           int inValue = getIpV4Value(ipV4);
223           if(inValue >= IpCTypeRange[0] && inValue <= IpCTypeRange[1])
224           {
225                return IP_C_TYPE;
226           }
227           else if(inValue >= IpBTypeRange[0] && inValue <= IpBTypeRange[1])
228           {
229                return IP_B_TYPE;
230           }
231           else if(inValue >= IpATypeRange[0] && inValue <= IpATypeRange[1])
232           {
233                return IP_A_TYPE;
234           }
235           return IP_OTHER_TYPE;
236      }
237     
238      /**
239      * 获取默认mask值,如果IpV4是A类地址,则返回{@linkplain #DefaultIpAMask},
240      * 如果IpV4是B类地址,则返回{@linkplain #DefaultIpBMask},以此类推
241      * @param anyIpV4 任何合法的IpV4
242      * @return mask 32bit值
243      */
244      public static int getDefaultMaskValue(String anyIpV4)
245      {
246           int checkIpType = checkIpV4Type(anyIpV4);
247           int maskValue = 0;
248           switch (checkIpType)
249           {
250                case IP_C_TYPE:
251                     maskValue = DefaultIpCMask;
252                     break;
253                case IP_B_TYPE:
254                     maskValue = DefaultIpBMask;
255                     break;
256                case IP_A_TYPE:
257                     maskValue = DefaultIpAMask;
258                     break;
259                default:
260                     maskValue = DefaultIpCMask;
261           }
262           return maskValue;
263      }
264     
265      /**
266      * 获取默认mask地址,A类地址对应255.0.0.0,B类地址对应255.255.0.0,
267      * C类及其它对应255.255.255.0
268      * @param anyIp
269      * @return mask 字符串表示
270      */
271      public static String getDefaultMaskStr(String anyIp)
272      {
273           return trans2IpStr(getDefaultMaskValue(anyIp));
274      }
275     
276      /**
277      * 将ip 32bit值转换为如“192.168.0.1”等格式的字符串
278      * @param ipValue 32bit值
279      * @return
280      */
281      public static String trans2IpStr(int ipValue)
282      {
283           // 保证每一位地址都是正整数
284           return ((ipValue >> 24) & 0xff) + "." + ((ipValue >> 16) & 0xff) + "." + ((ipValue >> 8) & 0xff) + "." + (ipValue & 0xff);
285      }
286     
287      /**
288      * 将ip byte数组值转换为如“192.168.0.1”等格式的字符串
289      * @param ipBytes 32bit值
290      * @return
291      */
292     public static String trans2IpV4Str(byte[] ipBytes)
293     {
294          // 保证每一位地址都是正整数
295          return (ipBytes[0] & 0xff) + "." + (ipBytes[1] & 0xff) + "." + (ipBytes[2] & 0xff) + "." + (ipBytes[3] & 0xff);
296     }
297 
298      public static int getIpV4Value(String ipOrMask)
299      {
300           byte[] addr = getIpV4Bytes(ipOrMask);
301           int address1  = addr[3] & 0xFF;
302           address1 |= ((addr[2] << 8) & 0xFF00);
303           address1 |= ((addr[1] << 16) & 0xFF0000);
304           address1 |= ((addr[0] << 24) & 0xFF000000);
305           return address1;
306      }
307 
308      public static byte[] getIpV4Bytes(String ipOrMask)
309      {
310           try
311           {
312                String[] addrs = ipOrMask.split("\\.");
313                int length = addrs.length;
314                byte[] addr = new byte[length];
315                for (int index = 0; index < length; index++)
316                {
317                     addr[index] = (byte) (Integer.parseInt(addrs[index]) & 0xff);
318                }
319                return addr;
320           }
321           catch (Exception e)
322           {
323           }
324           return new byte[4];
325      }
326 }

应用

  public static void main(String[] args) throws UnknownHostException
      {
             // 判断ip两个地址的大小关系
            String ip1 = "10.8.9.116";
            String ip2 = "10.8.9.10";
            System. out.println("ip1 大于 ip2? " + (compareIpV4s (ip1, ip2) > 0));

            String ip3= "10.8.8.116";
            String ip4 = "10.10.9.10";
            
            System. out.println("ip3 大于 ip4? " + (compareIpV4s (ip3, ip4) > 0));
            
             // 判断ip两个地址是否是同一个网段
             int mask1 = getIpV4Value( "255.255.255.0");
             int mask2 = getIpV4Value( "255.255.0.0");
            
            System. out.println("ip1和ip2在同一个网段中? " + (checkSameSegment(ip1, ip2, mask1)));
            
            System. out.println("ip3和ip4在同一个网段中 ?" + (checkSameSegment(ip3, ip4, mask2)));
            
             // 判断ip5是否在ip1和ip2范围中
            String ip5= "10.8.8.8";
                   // 假设ip1和ip2在同一个网段中,并且ip1为起始地址,ip2为结束地址,ip1<=1
                   // 比较ip1与ip5是否在同一个网段中
                   if(checkSameSegment(ip1, ip5, mask1))
                  {
                         // 判断ip5是否在ip1和ip2范围中
                         if(((compareIpV4s(ip5, ip1)) >= 0) && (compareIpV4s(ip5, ip2) <= 0))
                        {
                              System. out.println("ip5 在ip1-ip2范围内" );
                        }
                         else if ((compareIpV4s(ip5, ip1)) < 0)
                        {
                              System. out.println("ip5 不在ip1-ip2范围内,因为ip5小于ip1" );
                        }
                         else
                        {
                              System. out.println("ip5 不在ip1-ip2范围内,因为ip5大于ip2" );
                        }
                  }
                   else
                  {
                        System. out.println("ip5 不在ip1-ip2范围内,因为ip5不在ip1的网段中" );
                  }
      }
总结
 
  • 了解正在表达式,并懂得编写判断IP地址是否合法的表达式

  • 了解判断IpV4地址是否在同一个网段的原理,并能够用Java语言实现

优化与扩展
  • 另一种判断IpV4地址合法性的方法(不通过正在表达式)

  • 判断IpV4是否是A类地址,或者B类地址,又或者是广播地址等

  • 多个IpV4地址是否在同一个网段中

  • 客户端,服务器端安全策略实现——限制特点的用户IP登录系统

推荐阅读