100分讨论一个关于验证IP是否在定义范围内的算法

little_fairycat 2010-02-25 04:24:33
软件允许用户定义可登录的IP范围,允许多种格式多种定义添加,比如*.*.*.*,192.168.*.*,192.168.125.*这样的格式,在数据库里的对应字段allowableIP为varchar(4000),每个IP之间用分号来分隔。
这样,用户定义的一个allowableIP也许会出现如下形式
192.168.245.*;192.168.125.*;192.168.251.254;192.168.*.*;192.*.*.*;
当用户登录的时候,软件服务端首先要验证来自客户端的IP是否在允许的范围内。
比如这个来自客户端的srcIP为192.168.251.111
1.用indexOf看一下allowableIP是否有*.*.*.*,有的话就一律通过;
2.把allowableIP分解成一个arraylist
3.解析出srcIP的首地址为192,去匹配是否有192或者*打头的字符串,如果有打头就不是192或者*的,直接剔除
3.然后解析出srcIP的第二个地址为168,去匹配第二个地址是否有168,或者*,不是的直接删除
4.然后解析出srcIP的第三个地址,去匹配是否有251,或者*,不是的直接删除
5.然后解析出srcIP的第四个地址,去匹配是否有111,或者*,不是的直接删除
6.剩下的就是匹配的值,只要这个arraylist.size()>0,就是匹配

觉得这个算法效率很一般,不知道有没有更好更快的方法?
...全文
416 28 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 15 楼 little_fairycat 的回复:
12楼的,没有考虑通配符*的情况,就没有测试

13楼的代码我使用不同数据测试了一下,是正确可用的

6楼的我测试了一下,当测试数据改成
String []testIps = new String[]{"192.168.1.1","192.168.256.1","192.168.253.1"};
的时候,应该有两个合理地址,即192.168.1.1和192.168.253.1,但是结果只返回了192.168.1.1,我对正则不大懂,不知道错在什么地方


通配符?
192.168.1.* = 192.168.1.0/24 = 192.168.1.0/255.255.255.0 = 192.168.1.0 - 192.168.1.255
这是常识
wenjjing2lianee 2010-02-26
  • 打赏
  • 举报
回复
引用 3 楼 nanman 的回复:
很简单
把IP转换为整数,判断是否在整数范围内就可以


这个可以.

正则也行.
测试下看哪种效率更好.....
xierangh 2010-02-26
  • 打赏
  • 举报
回复
上面少点了哦((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
xierangh 2010-02-26
  • 打赏
  • 举报
回复
(2[0-4]\d|25[0-5]|[01]?\d\d?){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
little_fairycat 2010-02-26
  • 打赏
  • 举报
回复
原来是这样啊
我要好好学习一下正则了
jianghuxiaoxiami 2010-02-26
  • 打赏
  • 举报
回复
引用 15 楼 little_fairycat 的回复:
6楼的我测试了一下,当测试数据改成
String []testIps = new String[]{"192.168.1.1","192.168.256.1","192.168.253.1"};
的时候,应该有两个合理地址,即192.168.1.1和192.168.253.1,但是结果只返回了192.168.1.1,我对正则不大懂,不知道错在什么地方

更正6楼的程序,那个匹配0-255的正则我用 [0-255]是错误的,实际上[0-255]是匹配了0-2之间的,5,5也就是能匹配0,1,2,5这4个数,因此要匹配[0-255]应该“(([0-9])|([1-9][0-9])|([1-2][0-5][0-5]))”
测试如下

public class Test {

public static void main(String []args){
String ipRule = "192.168.*.*";
String ipReg = ipRule.replace(".", "\\.").replace("*", "(([0-9])|([1-9][0-9])|([1-2][0-5][0-5]))");//把IP规则替换为正则
String []testIps = new String[]{"192.168.1.555","192.168.256.1","192.168.253.10"};
for(String tempIp:testIps){
if(tempIp.matches(ipReg)){
System.out.println("合法IP: "+tempIp);
}
}
}

}
lzlwzs04 2010-02-26
  • 打赏
  • 举报
回复
mark一下 学习学习
little_fairycat 2010-02-26
  • 打赏
  • 举报
回复
12楼的,没有考虑通配符*的情况,就没有测试

13楼的代码我使用不同数据测试了一下,是正确可用的

6楼的我测试了一下,当测试数据改成
String []testIps = new String[]{"192.168.1.1","192.168.256.1","192.168.253.1"};
的时候,应该有两个合理地址,即192.168.1.1和192.168.253.1,但是结果只返回了192.168.1.1,我对正则不大懂,不知道错在什么地方

码之魂 2010-02-26
  • 打赏
  • 举报
回复
用正则就搞定了。。。接分闪人。。。
  • 打赏
  • 举报
回复
不用那么复杂
package com.saturday.string;

public class IPMatcher {
public static void main(String[] args){
String allowIp="192.168.245.*;192.168.125.*;192.168.251.254;192.168.*.*;192.*.*.*;";
String ip="192.168.251.111";

System.out.println(isIPAllow(allowIp,ip));
}

public static boolean isIPAllow(
String allowIp,
String ip){

String
s1=ip,
s2=ip.replaceAll("\\.\\d+$", ".*"),
s3=ip.replaceAll("\\.\\d+\\.\\d+$", ".*.*"),
s4="*.*.*.*";

if(allowIp.indexOf(s1)>-1) return true;
if(allowIp.indexOf(s2)>-1) return true;
if(allowIp.indexOf(s3)>-1) return true;
if(allowIp.indexOf(s4)>-1) return true;

return false;
}
}
  • 打赏
  • 举报
回复
  //将127.0.0.1形式的IP地址转换成十进制整数,这里没有进行任何错误处理  
public static long ipToLong(String strIp) ...{
long[] ip = new long[4];
//先找到IP地址字符串中.的位置
int position1 = strIp.indexOf(".");
int position2 = strIp.indexOf(".", position1 + 1);
int position3 = strIp.indexOf(".", position2 + 1);
//将每个.之间的字符串转换成整型
ip[0] = Long.parseLong(strIp.substring(0, position1));
ip[1] = Long.parseLong(strIp.substring(position1+1, position2));
ip[2] = Long.parseLong(strIp.substring(position2+1, position3));
ip[3] = Long.parseLong(strIp.substring(position3+1));
return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
}

不转整数,就要考虑127.001.001.001的格式
slmvpvip 2010-02-26
  • 打赏
  • 举报
回复
引用 10 楼 py330316117 的回复:
引用 3 楼 nanman 的回复:
很简单
把IP转换为整数,判断是否在整数范围内就可以
ip是带十进制界点的,你怎么装换成整数,而且这么做很容易超过int的范围。个人认为6楼用正则很好

先转换成string,然后去掉“.”,再转换成整数。int不行就用long
py330316117 2010-02-26
  • 打赏
  • 举报
回复
引用 3 楼 nanman 的回复:
很简单
把IP转换为整数,判断是否在整数范围内就可以

ip是带十进制界点的,你怎么装换成整数,而且这么做很容易超过int的范围。个人认为6楼用正则很好
abc130314 2010-02-26
  • 打赏
  • 举报
回复
如果存 数据库的话。那你可以把 192.168.125.*,存进4个int字段,192-168-125-(-1)
然后select count(id) from table where (a1=192 or a1=-1) and (a2=163 or a2=-1) ...
(不过速度未知,有待测试)
lwhzhl 2010-02-26
  • 打赏
  • 举报
回复
顶...........
  • 打赏
  • 举报
回复
引用 24 楼 jianghuxiaoxiami 的回复:
火龙果也太有精神了,不过就为了验证IP写那么一堆是不是太繁琐了


实际上也没多少代码,IpUtil 只是一个工具类是一次工作,大多数的代码都在这里,都是一些 IP 字符串与 IP 值之间的转换。其他两个类的代码也不是很多呀。
jianghuxiaoxiami 2010-02-26
  • 打赏
  • 举报
回复
火龙果也太有精神了,不过就为了验证IP写那么一堆是不是太繁琐了
gavin_FLY 2010-02-26
  • 打赏
  • 举报
回复
jf 学习学习中..................
  • 打赏
  • 举报
回复
这样的表结构设计得就不是很好,如果改成这样的话会更好一些

1. ID              NUMBER(9)      PK
2. START_IP VARCHAR2(15)
3. END_IP VARCHAR2(15)
4. START_IP_VALUE NUMBER(10) 根据 START_IP 转成的数值
5. END_IP_VALUE NUMBER(10) 根据 END_IP 转成的数值


192.168.245.*;192.168.125.*;192.168.251.254;192.168.*.*;192.*.*.*; 存为

ID  START_IP         END_IP           START_IP_VALUE  END_IP_VALUE 
------------------------------------------------------------------
1 192.168.245.0 192.168.245.255 3232298240 3232298495
2 192.168.125.0 192.168.125.255 3232267520 3232267775
3 192.168.251.254 192.168.251.254 3232300030 3232300030
4 192.168.0.0 192.168.255.255 3232235520 3232301055
5 192.0.0.0 192.255.255.255 3221225472 3238002687


如果数据存储不能更改的话,那么可以这样做:

public class IpTest {

public static void main(String[] args) {
String ips = "192.*.*.*;192.168.125.*;192.168.251.254;192.168.245.*;192.168.*.*";
IpContent content = new IpContent(ips);
System.out.println(content.contains("193.173.0.1"));
}
}
import java.util.Arrays;
import java.util.regex.Pattern;

public class IpContent {

private final static String DEFAULT_SEPARATOR = ";";

private IpScope[] ipScopes;

public IpContent(String ips) {
this( ips, DEFAULT_SEPARATOR);
}

public IpContent(String ips, String separator) {
this( ips.split(Pattern.quote(separator)) );
}

public IpContent(String[] ipsArray) {
init(ipsArray);
}

public boolean contains(String ip) {
if(ipScopes == null || ipScopes.length == 0) {
return false;
}
long ipValue = IpUtil.ip2Number(ip);
for(int i = 0; i < ipScopes.length; i++) {
if(ipScopes[i].contains(ipValue)) {
return true;
}
}
return false;
}

private void init(String[] ipsArray) {
if(ipsArray == null || ipsArray.length == 0) {
return;
}
ipScopes = new IpScope[ipsArray.length];
for(int i = 0; i < ipsArray.length; i++) {
ipScopes[i] = new IpScope(ipsArray[i]);
}
Arrays.sort(ipScopes);
}

public String toString() {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < ipScopes.length; i++) {
sb.append(ipScopes[i]).append("\n");
}
return sb.toString();
}
}
public class IpScope implements Comparable<IpScope> {

public final static String FUZZY_PLACEHOLDER = "*";
public final static String IP_MIN_VALUE = "0";
public final static String IP_MAX_VALUE = "255";

private String ip;

private long startIpValue;
private long endIpValue;

IpScope(String ip) {
this.ip = ip;
processIpValue();
}

public String getIp() {
return ip;
}
public String getStartIp() {
return IpUtil.number2Ip(startIpValue);
}
public String getEndIp() {
return IpUtil.number2Ip(endIpValue);
}
public long getStartIpValue() {
return startIpValue;
}
public long getEndIpValue() {
return endIpValue;
}

public boolean contains(long ipValue) {
return (ipValue >= startIpValue) && (ipValue <= endIpValue);
}

private long diff() {
return endIpValue - startIpValue;
}

private void processIpValue() {
String[] ips = ip.split("\\.");
startIpValue = toNumber(ips.clone(), IP_MIN_VALUE);
endIpValue = toNumber(ips.clone(), IP_MAX_VALUE);
}

private long toNumber(String[] ips, String defaultValue) {
for(int i = 0; i < ips.length; i++) {
ips[i] = ips[i].trim();
if(FUZZY_PLACEHOLDER.equals(ips[i])) {
ips[i] = defaultValue;
}
}
return IpUtil.ip2Number(ips);
}

public int compareTo(IpScope o) {
long diff = this.diff() - o.diff();
if(diff > Integer.MAX_VALUE) {
return Integer.MIN_VALUE;
}
return -(int)diff;
}

public String toString() {
return "IP pattern: " + ip + ", start: " + getStartIp() + ", end: " + getEndIp();
}
}
public class IpUtil {

/**
* 将 IP 字符串转为 long 数据
* @param ip
* @return
* @author frankiegao123
* 2010-2-26 下午03:47:14
*/
public static long ip2Number(String ip) {
String[] s = ip.split("\\.");
return ip2Number(s);
}

public static long ip2Number(String[] ips) {
long ipn = 0L;
for (int i = 0; i < ips.length; i++) {
ipn = (ipn << 8) | Long.parseLong(ips[i]);
}
return ipn;
}

/**
* 以字符串形式表示的 IP 地址
* @param number
* @return
* @author frankiegao123
* 2010-2-26 下午03:47:35
*/
public static String number2Ip(long number) {
char[] chs = new char[15];
int offset = 0;
for (int i = 1; i <= 4; i++) {
if(i > 1) {
chs[offset++] = '.';
}
int shift = (4 - i) * 8;
int n = (int) ((number & (0xff << shift)) >>> shift);
offset = putChar(chs, offset, n);
}
return new String(chs, 0, offset);
}

private static int putChar(char[] chs, int offset, int number) {
int len = length(number);
int t = len;
while(t > 0) {
chs[--t + offset] = (char)('0' + number % 10);
number /= 10;
}
return offset + len;
}

private static int length(int number) {
int len = 1;
while(number > 9) {
number /= 10;
len++;
}
return len;
}
}
shan1119 2010-02-25
  • 打赏
  • 举报
回复
3楼的方法很好。 回复内容太短了!
加载更多回复(8)
# 主成析PCA降维算法Python实现 - 数据降维和特征提取 ## 项目简介 本项目提供了主成析(Principal Component Analysis, PCA)算法的完整Python实现,包含从数据预处理到结果可视化的全套功能。PCA是一种经典的无监督降维算法,通过线性变换将高维数据投影到低维空间,同时保持数据的最大方差,广泛应用于数据降维、特征提取、数据可视化等领域。 ### 功能特点 - **完整的PCA算法实现**:包含数据标准化、协方差矩阵计算、特征值解等核心步骤 - **多种数据生成器**:内置多种类型的测试数据生成功能 - **丰富的可视化功能**:支持解释方差图、散点图、双图、热力图等多种可视化方式 - **灵活的参数配置**:支持自定义主成数量、标准化选项等 - **全面的析工具**:包含特征重要性析、重构误差计算、最优成数量确定等 - **详细的示例代码**:提供多个应用场景的完整示例 ## 安装说明 安装依赖 ```bash pip install -r requirements.txt ``` ## 使用说明 ```bash # 运行所有演示 pytho ```bash # 运行所有演示 python main.py --demo all # 运行特定演示 python main.py --demo iris # 鸢尾花数据集析 python main.py --demo high_dim # 高维数据降维 python main.py --demo correlated # 相关性数据析 python main.py --demo comprehensive # 综合析 # 指定输出目录 python main.py --output results ```
基于Javaweb的机房管理系统的设计与实现编程环境:idea2022平台,jdk1.8,tomcat8.5编程语言:java语言,编程技术:前端vue,div,css,后端:springboot框架,数据库:mysql5.7版本,Navicat Premium 12插件前台+后台前台学生注册,登录机房安全公告列表, 点击查看详情机房信息列表(点击搜索机房,查看到机房的详细情况)上机预约:选择机房,查看电脑信息,显示多少台电脑,点击可以查看机房的电脑详情,多少空闲的,点击可以预约电脑(填写预约时间,预约人)机房消防检公布设备故障上报:注册的学生也可以进行设备故障报修后台管理员管理员信息管理机房安全公告管理机房消防检查管理(记录每次的消防检查,对检查结果进行公布)教师信息管理维修人员管理注册学生管理,审核机房信息管理(多个机房)设备信息管理(电脑设备)填写CPU,内存,品牌,显卡等基本信息日志信息管理教师教师资料修改机房上机预约管理软件设备报修,查看维修结果硬件设备报修,查看维修结果上机信息管理:设置上机信息,下机信息,查看上机时间,查看到历史上机信息维修人员资料信息修改软件设备报修管理,填写维修结果硬件设备报修管理,填写维修结果设备故障报修管理:主要是针对学生前台提交的报修进行管理,处理学生学生资料修改我的预约信息我的上机:点击选择某个电脑进行上机,只能选择预约同意的电脑进行上机,我的下机:上机结束后,点击可以下机,并且计算出上机时间我的历史上机我的设备故障报修管理

62,630

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧