放翁(文初)的一亩三分地

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  210 随笔 :: 1 文章 :: 320 评论 :: 0 Trackbacks
    下面是一段简单的判断一个ip是否在一组ip中的函数,其中ip和ip组的表达方式可以为这样(ip="192.3.22.34",iplist="123.21.23.11,121.2.11.234,12.*.23.*"),下面红色部分是开始一个同学写的,蓝色部分是后来我尝试修改的。要说明的就以下几点:
     1.很多时候优化可以在海量运算之前做好准备,例如分析的数据先做预处理,因为往往可读性和计算效率会有冲突。
     2.如果没有缓存,那么构建利于高效计算的代价可能超出简单但计算效率一般的情况。
     3.在数据量很大的情况下,如何节省存储直接决定你是否能够缓存这些数据用于下次计算。

    有兴趣的同学可以执行以下下面一些代码(拷贝到eclipse格式化看和执行比较好):
    改动的主要内容在于对数据作预处理时增加了一点转换,6位byte作为支持ipv6的存储,第7位作为标识位来便于避免不需要的比对。
    用到了org.apache.commons.lang.StringUtils,它的split方法就是采用简单的substring而不是pattern,效率很高,特别对于海量计算。

   具体的测试代码:
   public static void  main(String[] args)
 {
  long beg = System.currentTimeMillis();
  
  //下面这些代码是用于存粹比较计算时,对白名单做预编译和缓存
  byte[][] whiteIps = prepare("12.24.23.123,12.25.23.255,12.24.23.17,*.25.*.*,12.24.*.*");
  
  String[] allowIps = StringUtils.split("12.24.23.123,12.25.23.255,12.24.23.17,*.25.*.*,12.24.*.*",",");
  List<String[]> whiteIps2 = new ArrayList<String[]>();
  if (null != allowIps && allowIps.length > 0) {
   for (int i = 0; i < allowIps.length; i++) {
    //把每个ip按“.”拆开,得到一个四位的数组
    String[] ipParse = StringUtils.split(allowIps[i], ".");
    whiteIps2.add(ipParse);
   }
  }
  
  for(int i = 0 ; i < 1000000 ; i++)
  {
   //第一组对比,增加了多一点的预处理,性能下降
   //checkAppIpWhite("12.24.23.123,12.25.23.255,12.24.23.17,*.25.*.*,12.24.*.*","12.24.23.19");
   //checkAppIpWhite("12.24.23.123,12.25.23.255,12.24.23.17,*.25.*.*,12.24.*.*","12.24.23.11");
   //checkAppIpWhiteV2("12.24.23.123,12.25.23.255,12.24.23.17,*.25.*.*,12.24.*.*","12.24.23.19");
   //checkAppIpWhiteV2("12.24.23.123,12.25.23.255,12.24.23.17,*.25.*.*,12.24.*.*","12.24.23.11");
   
   //存粹的比较计算,性能上升
//   checkAppIpWhite(whiteIps2,"12.24.23.19");
//   checkAppIpWhite(whiteIps2,"12.24.23.11");  
   checkAppIpWhiteV2(whiteIps,"12.24.23.19");
   checkAppIpWhiteV2(whiteIps,"12.24.23.11");
  }
  
  System.out.println("end test : " +  (System.currentTimeMillis() - beg));
 }


老的比较代码函数如下:
public static boolean checkAppIpWhite(String ipWhilte,String remoteIp){
  if(StringUtils.isEmpty(ipWhilte) || StringUtils.isEmpty(remoteIp)){
   return true;
  }
  String[] allowIps = StringUtils.split(ipWhilte,",");
  List<String[]> whiteIps = new ArrayList<String[]>();
  if (null != allowIps && allowIps.length > 0) {
   for (int i = 0; i < allowIps.length; i++) {
    //把每个ip按“.”拆开,得到一个四位的数组
    String[] ipParse = StringUtils.split(allowIps[i], ".");
    whiteIps.add(ipParse);
   }
  }
  String[] requestParse = StringUtils.split(remoteIp, ".");
  for (String[] whiteIp : whiteIps) {
   if (ipsEqual(requestParse, whiteIp)) {
    return true;
   }
  }
  return false;
 }
 
 public static boolean checkAppIpWhite(List<String[]> whiteIps,String remoteIp){
  String[] requestParse = StringUtils.split(remoteIp, ".");
  for (String[] whiteIp : whiteIps) {
   if (ipsEqual(requestParse, whiteIp)) {
    return true;
   }
  }
  return false;
 }
 
 //判断两个ip是否相等
 public static boolean ipsEqual(String[] requestIp, String[] whiteIp) {
  boolean equal = false;
  
  //判断白名单ip是否在列表中必须要两个ip都不为空进行比较
  if (requestIp != null && whiteIp != null && requestIp.length == whiteIp.length) {   
   if (requestIp[0].equals(whiteIp[0])
     && requestIp[1].equals(whiteIp[1])
     && ("*".equals(whiteIp[2]) || requestIp[2]
       .equals(whiteIp[2]))
     && ("*".equals(whiteIp[3]) || requestIp[3]
       .equals(whiteIp[3]))) {
    equal = true;
   }
  }
  
  return equal;
 }

    

新的代码:
public static boolean checkAppIpWhiteV2(String ipWhite,String remoteIp){
  
  if(StringUtils.isEmpty(ipWhite) || StringUtils.isEmpty(remoteIp)){
   return true;
  }
  
  byte[][] whiteIps = prepare(ipWhite);
  
  byte[] rIp = convertIp2Bytes(remoteIp);
  
  return isInclude(whiteIps,rIp);
  
 }
 
 public static boolean checkAppIpWhiteV2(byte[][] whiteIps,String remoteIp)
 {
  byte[] rIp = convertIp2Bytes(remoteIp);
  
  return isInclude(whiteIps,rIp);
 }
 
 public static  boolean isInclude(byte[][] whiteIps,byte[] rIp)
 {
  boolean result = false;
  
  for(byte[] whiteIp : whiteIps)
  {
   for(int i = 1; i < 7; i++)
   {
    byte n = (byte)(1 << (i-1));
    
    if ((whiteIp[0] & n) != n)
    {
     if (i == 6)
      return true;
     else
      continue;
    }
    else
    {
     if (whiteIp[i] != rIp[i-1])
      break;
    }
    
    
    if (i == 6)
    {
     return true;
    }
   }
  }
  
  return result;
 }
 
 public static byte[] convertIp2Bytes(String remoteIp)
 {
  byte[] result = new byte[6];
  
  String[] points = StringUtils.split(remoteIp,".");
  
  int cursor = 0;
  
  for(String point : points)
  {
   int i = Integer.parseInt(point);
   
   if (i > Byte.MAX_VALUE)
    result[cursor] = (byte)(i - Byte.MAX_VALUE);
   else
    result[cursor] = (byte)i; 
   
   cursor += 1;
  }
  
  return result;
 }
 
 public static byte[][] prepare(String ipWhite)
 {
  String[] allowIps = StringUtils.split(ipWhite,",");//性能很好
  byte[][] result = new byte[allowIps.length][7];
  
  int cursorX = 0;
  
  for(String allowIp : allowIps)
  {
   String[] points = StringUtils.split(allowIp,".");
   
   int cursorY = 0;
   byte checkbits = 0;
   
   for(String point : points)
   {
    if (!point.equals("*"))
    {
     checkbits += 1 << cursorY;
     
     int i = Integer.parseInt(point);
     
     if (i > Byte.MAX_VALUE)
      result[cursorX][cursorY + 1] = (byte)(i - Byte.MAX_VALUE);
     else
      result[cursorX][cursorY + 1] = (byte)i; 
    }
    cursorY += 1;
   }
   
   result[cursorX][0] = checkbits;
   cursorX += 1;
  }
  
  return result;
  
 }
   
posted on 2011-04-13 23:11 岑文初 阅读(4574) 评论(1)  编辑  收藏

评论

# re: 一段代码,几句话 2011-04-28 10:46 北京王铮
这个还可以再进一步优化下吧  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问