请大家帮忙看看我的代码,限制机器人访问网站 本帖最后由 ArayChou 于 2010-04-20 18:16:23 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 /** * @author Aray Chou * Email: Aray(dot)Chou(dot)CN(at)gmail(dot)com * Replace "(dot)" with "." and replace "(at)" with "@" */package com.aray.core.common;/** * 常量 */public class Constants{ /** 访问频率控制,单位毫秒, 现在的值为30秒 */ public static int REQUEST_CONTROL_PERIOD = 10 * 1000; /** 访问频率控制,在一端时间内的最大访问次数 */ public static int REQUEST_CONTROL_ALLOW_TIMES = 10; /** 访问频率控制,最小不能访问的时间,这个时间段内,必须输入验证码后才能访问系统 */ public static int REQUEST_CONTROL_BAN_TIME = 10 * 1000; /** 访问频率控制,检查时间间隔 */ public static int REQUEST_CONTROL_CHECK_INTERVAL = 60 * 1000;} /** * @author Aray Chou * Email: Aray(dot)Chou(dot)CN(at)gmail(dot)com * Replace "(dot)" with "." and replace "(at)" with "@" */package com.aray.core.filter;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.Collections;import java.util.HashSet;import java.util.Hashtable;import java.util.Map;import java.util.Set;import com.aray.core.common.Constants;/** * <p> * 控制访问频率 * </p> * 如果用户的ip在 {@link com.aray.core.common.Constants#REQUEST_CONTROL_PERIOD}内的请求数大于等于 * {@link com.aray.core.common.Constants#REQUEST_CONTROL_ALLOW_TIMES},则标记此ip为"超出控制" * 超出控制的ip的用户必须输入验证码后马上访问系统。如果没有输入验证码,此状态在[{@link com.aray.core.common.Constants#REQUEST_CONTROL_BAN_TIME}, * {@link com.aray.core.common.Constants#REQUEST_CONTROL_BAN_TIME} + * {@link com.aray.core.common.Constants#REQUEST_CONTROL_CHECK_INTERVAL}]后,系统自动解除控制。 * */public class RequestControl{ /** 所有control对象,在此对象rehash的时候,会清除里面超时的control */ private static MyHashtable<String, RequestControl> controls = new MyHashtable<String, RequestControl>(1000); /** 超过控制的control对象,系统会开线程自动清除里面超时的control */ private static Set<RequestControl> outofControlObject = Collections.synchronizedSet(new HashSet<RequestControl>()); static { // 新开线程,清理超时的control Runnable run = new Runnable() { @Override public void run() { while (true) { ArrayList<RequestControl> timeout = new ArrayList<RequestControl>(); for (RequestControl c : outofControlObject) { if (c.isTimeOut()) timeout.add(c); } for (RequestControl c : timeout) c.timeOutClear(); try { Thread.sleep(Constants.REQUEST_CONTROL_CHECK_INTERVAL); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread t = new Thread(run); t.setDaemon(true); t.setName("RequestControlCleaner"); t.start(); } /** * 检查客户端是否超过访问限制 * * @param ip * 客户端ip * @return 超过访问限制,返回true */ public static boolean over(String ip) { RequestControl control = controls.get(ip); // 第一个访问,新建control对象 if (control == null) { control = new RequestControl(); controls.put(ip, control); return false; } // 已经超过控制 if (control.outOfControl) return true; // 设置事件时间 control.time = System.currentTimeMillis(); boolean result = !control.queue.appendCurentTime(); // 队列已满,超过访问控制 if (result) { control.queue.reset(); control.outOfControl = true; // 将超过控制的control对象放在这里,系统会定期检查,自动移除超时的control outofControlObject.add(control); } return control.outOfControl; } /** * 如果ban的时间超过 {@link com.aray.core.common.Constants.REQUEST_CONTROL_BAN_TIME}, 重置outOfControl为false, * 同时从outofControls中移出当前对象 */ protected void timeOutClear() { // 重置访问控制状态为不受限制 if (isTimeOut()) { outofControlObject.remove(this); this.outOfControl = false; } } /** * ban的时间是否超过限制 * * @return 是否超时 */ protected boolean isTimeOut() { return System.currentTimeMillis() - this.time >= Constants.REQUEST_CONTROL_BAN_TIME; } private RuquestControlQueue queue; /** 标志当前ip是否已经超出控制 */ private boolean outOfControl = false; /** 事件发生时间 */ private long time; private RequestControl() { this.queue = new RuquestControlQueue(Constants.REQUEST_CONTROL_ALLOW_TIMES); } /** * 消除警报 * * @param ip */ public static void clearAlarm(String ip) { RequestControl control = controls.get(ip); if (control != null) control.outOfControl = false; } /** *重载 {@link java.util.Hashtable#rehash()},在rehash之前,现移除超时的control。 *如果移除超时的control后,仍然需要rehash,调用HashTable.rehash() * * @param <K> * @param <V> */ static public class MyHashtable<K, V> extends Hashtable<K, V> { private static final long serialVersionUID = 1L; /** * @param initialCapacity * @param loadFactor */ public MyHashtable(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } /** * */ public MyHashtable() { super(); } /** * @param initialCapacity */ public MyHashtable(int initialCapacity) { super(initialCapacity); } /* * (non-Javadoc) * * @see java.util.Hashtable#rehash() */ @Override protected void rehash() { removeTimeout(); // 移除超时的control后,当前的大小 int count = this.size(); // 通过反射的到HashMap.threshold int threshold = getThreshold(); // 移除后,如果仍然需要扩展,则扩展hashTable if (count >= threshold) super.rehash(); } /** * 通过反射的到HashMap.threshold * * @return */ private int getThreshold() { int threshold = 0; try { Field field = this.getClass().getSuperclass().getDeclaredField("threshold"); field.setAccessible(true); threshold = (Integer) field.get(this); } catch (Exception e) { System.out.println("System Error, probably wrong JRE version"); e.printStackTrace(); System.exit(-1); } return threshold; } /** * 删除超时的control */ private void removeTimeout() { ArrayList<K> key = new ArrayList<K>(100); // 得到所有超时的key for (Map.Entry<K, V> entry : this.entrySet()) { V value = entry.getValue(); if (value instanceof RequestControl) { RequestControl control = (RequestControl) value; if (control.isTimeOut()) { key.add(entry.getKey()); } } } // 删除对应的control for (K k : key) { this.remove(k); } } }} /** * @author Aray Chou * Email: Aray(dot)Chou(dot)CN(at)gmail(dot)com * Replace "(dot)" with "." and replace "(at)" with "@" */package com.aray.core.filter;import com.aray.core.common.Constants;/** * 请求控制队列。每有一个请求,移出队列过期的时间戳,然后往此队列里加入当前时间戳. * 如果队列已满,则认为超出请求控制的频度要求。 * <p> * 算法: * <ul> * <li>用一个定长数组存储数据,first指向第一个元素。size表示总元素过数。</li> * <li>追加数据时候,有可能发生first+size>data.length的情况。这个时候,折回从数组开始插入数据</li> * </ul> * </p> */public class RuquestControlQueue{ /** 第一个元素的下标 */ protected int first; /** 队列的长度,总元素个数 */ protected int size; /** 队列的元素 */ protected long[] data; /** * @param length * 队列的长度 */ public RuquestControlQueue(int length) { data = new long[length]; } /** * 移出过期数据,追加新的时间戳。 * * @return 如果队列已满,则追加失败,返回false. */ public boolean appendCurentTime() { this.removeExpired(); return this.append(System.currentTimeMillis()); } /** * 追加数据 * * @param value * @return 队列满,这追加失败,返回false */ public synchronized boolean append(long value) { if (size == data.length) return false; int position = (first + size) % data.length; data[position] = value; size++; return true; } /** * 重置队列,清空里面的数据 */ public synchronized void reset() { this.first = 0; this.size = 0; } /** * 删除 {@link com.aray.core.common.Constants.Constants.REQUEST_CONTROL_PERIOD}以前的过期数据。<br /> */ private void removeExpired() { long expired = System.currentTimeMillis() - Constants.REQUEST_CONTROL_PERIOD; // 删除过期的元素 this.removeLess(expired); } /** * 移除小于等于value的数据 * * @param value */ public synchronized void removeLess(long value) { // 删除过期的元素 if (this.size > 0) { int p = this.find(value, this.first, this.size); if (p != -1) { // 第一个元素指针指向p后的元素,移除下标p及其以前的数组元素 int newStart = (p + 1) % this.data.length; // 修改元素个数 this.size = this.size - (newStart + this.data.length - this.first) % this.data.length; this.first = newStart; } } } public static void main(String[] args) { RuquestControlQueue q = new RuquestControlQueue(20); q.first = 19; for (int i = 1; i < 14; i++) q.append(i); for (int i = 0; i < q.data.length; i++) { System.out.print(q.data[i]); if (i == q.first) System.out.print('*'); System.out.print(' '); } int xxx = 12; System.out.println("\n" + q.find(xxx)); q.out(); q.removeLess(xxx); q.out(); } /** * 在当前队列中,查找小于等于value的最后一个数据 * * @param value * @return 小于等于value的最后一个数据的下标 */ protected int find(long value) { return this.find(value, this.first, this.size); } /** * 折半查找,从数组position开始的size个数据中,查找最后一个小于等于value的元素 * * @param value * @param position * 开始位置 * @param size * @return 最后一个小于等于value的元素的下标 */ protected int find(long value, int position, int size) { if (this.size == 0 || this.data[this.first] > value /* value比第一个还小 */) return -1; // value比最后一个值还大 int lastPosition = (this.first + this.size - 1) % this.data.length; if (this.data[lastPosition] <= value) return lastPosition; if (size == 1) { if (this.data[position] <= value) return position; else return -1; } int half = size / 2; int halfPosition = (position + half) % this.data.length; if (this.data[halfPosition] > value) return find(value, position, half); else return find(value, halfPosition, size - half); } /** * 输出队列,测使用 */ protected void out() { for (int i = 0; i < this.size; i++) { int p = (this.first + i) % this.data.length; System.out.print(this.data[p] + " "); } System.out.println(); }} ADSL重新拨号换IP,如果换IP都不行,清空IE缓存,cookie这些试验下。 为什么不能防止多次启动呢? 域名上FCK显示不了是什么原因,在测试机上可以 JSP通过ODBC连接MSSQL的问题 晚上 struts2简单示例跑步起来,不知道哪里缺少配置 java socket半关闭问题 无法启动j2ee 求救 关于servlet编译后的问题!还请大大们指教!!! 郑重道歉《专心专著》群 struts2 重定向 传参数问题。 有个关于打印的问题? 如何用js实现添加项功能?页面在下边 ext中JsonReader 显示不出数据
/**
* @author Aray Chou
* Email: Aray(dot)Chou(dot)CN(at)gmail(dot)com
* Replace "(dot)" with "." and replace "(at)" with "@"
*/
package com.aray.core.common;/**
* 常量
*/
public class Constants
{ /** 访问频率控制,单位毫秒, 现在的值为30秒 */
public static int REQUEST_CONTROL_PERIOD = 10 * 1000; /** 访问频率控制,在一端时间内的最大访问次数 */
public static int REQUEST_CONTROL_ALLOW_TIMES = 10; /** 访问频率控制,最小不能访问的时间,这个时间段内,必须输入验证码后才能访问系统 */
public static int REQUEST_CONTROL_BAN_TIME = 10 * 1000; /** 访问频率控制,检查时间间隔 */
public static int REQUEST_CONTROL_CHECK_INTERVAL = 60 * 1000;}
/**
* @author Aray Chou
* Email: Aray(dot)Chou(dot)CN(at)gmail(dot)com
* Replace "(dot)" with "." and replace "(at)" with "@"
*/
package com.aray.core.filter;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;import com.aray.core.common.Constants;/**
* <p>
* 控制访问频率
* </p>
* 如果用户的ip在 {@link com.aray.core.common.Constants#REQUEST_CONTROL_PERIOD}内的请求数大于等于
* {@link com.aray.core.common.Constants#REQUEST_CONTROL_ALLOW_TIMES},则标记此ip为"超出控制"
* 超出控制的ip的用户必须输入验证码后马上访问系统。如果没有输入验证码,此状态在[{@link com.aray.core.common.Constants#REQUEST_CONTROL_BAN_TIME},
* {@link com.aray.core.common.Constants#REQUEST_CONTROL_BAN_TIME} +
* {@link com.aray.core.common.Constants#REQUEST_CONTROL_CHECK_INTERVAL}]后,系统自动解除控制。
*
*/
public class RequestControl
{
/** 所有control对象,在此对象rehash的时候,会清除里面超时的control */
private static MyHashtable<String, RequestControl> controls = new MyHashtable<String, RequestControl>(1000); /** 超过控制的control对象,系统会开线程自动清除里面超时的control */
private static Set<RequestControl> outofControlObject = Collections.synchronizedSet(new HashSet<RequestControl>()); static
{
// 新开线程,清理超时的control
Runnable run = new Runnable()
{
@Override
public void run()
{
while (true)
{
ArrayList<RequestControl> timeout = new ArrayList<RequestControl>();
for (RequestControl c : outofControlObject)
{
if (c.isTimeOut())
timeout.add(c);
} for (RequestControl c : timeout)
c.timeOutClear(); try
{
Thread.sleep(Constants.REQUEST_CONTROL_CHECK_INTERVAL);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
Thread t = new Thread(run);
t.setDaemon(true);
t.setName("RequestControlCleaner");
t.start();
} /**
* 检查客户端是否超过访问限制
*
* @param ip
* 客户端ip
* @return 超过访问限制,返回true
*/
public static boolean over(String ip)
{ RequestControl control = controls.get(ip); // 第一个访问,新建control对象
if (control == null)
{
control = new RequestControl();
controls.put(ip, control);
return false;
} // 已经超过控制
if (control.outOfControl)
return true; // 设置事件时间
control.time = System.currentTimeMillis(); boolean result = !control.queue.appendCurentTime(); // 队列已满,超过访问控制
if (result)
{
control.queue.reset();
control.outOfControl = true; // 将超过控制的control对象放在这里,系统会定期检查,自动移除超时的control
outofControlObject.add(control);
} return control.outOfControl; } /**
* 如果ban的时间超过 {@link com.aray.core.common.Constants.REQUEST_CONTROL_BAN_TIME}, 重置outOfControl为false,
* 同时从outofControls中移出当前对象
*/
protected void timeOutClear()
{ // 重置访问控制状态为不受限制
if (isTimeOut())
{
outofControlObject.remove(this);
this.outOfControl = false;
}
} /**
* ban的时间是否超过限制
*
* @return 是否超时
*/
protected boolean isTimeOut()
{
return System.currentTimeMillis() - this.time >= Constants.REQUEST_CONTROL_BAN_TIME;
} private RuquestControlQueue queue; /** 标志当前ip是否已经超出控制 */
private boolean outOfControl = false; /** 事件发生时间 */
private long time; private RequestControl()
{
this.queue = new RuquestControlQueue(Constants.REQUEST_CONTROL_ALLOW_TIMES);
} /**
* 消除警报
*
* @param ip
*/
public static void clearAlarm(String ip)
{
RequestControl control = controls.get(ip); if (control != null)
control.outOfControl = false;
} /**
*重载 {@link java.util.Hashtable#rehash()},在rehash之前,现移除超时的control。
*如果移除超时的control后,仍然需要rehash,调用HashTable.rehash()
*
* @param <K>
* @param <V>
*/
static public class MyHashtable<K, V> extends Hashtable<K, V>
{
private static final long serialVersionUID = 1L; /**
* @param initialCapacity
* @param loadFactor
*/
public MyHashtable(int initialCapacity, float loadFactor)
{
super(initialCapacity, loadFactor);
} /**
*
*/
public MyHashtable()
{
super(); } /**
* @param initialCapacity
*/
public MyHashtable(int initialCapacity)
{
super(initialCapacity);
} /*
* (non-Javadoc)
*
* @see java.util.Hashtable#rehash()
*/
@Override
protected void rehash()
{
removeTimeout(); // 移除超时的control后,当前的大小
int count = this.size(); // 通过反射的到HashMap.threshold
int threshold = getThreshold(); // 移除后,如果仍然需要扩展,则扩展hashTable
if (count >= threshold)
super.rehash();
} /**
* 通过反射的到HashMap.threshold
*
* @return
*/
private int getThreshold()
{
int threshold = 0;
try
{
Field field = this.getClass().getSuperclass().getDeclaredField("threshold");
field.setAccessible(true);
threshold = (Integer) field.get(this);
}
catch (Exception e)
{
System.out.println("System Error, probably wrong JRE version");
e.printStackTrace();
System.exit(-1);
}
return threshold;
} /**
* 删除超时的control
*/
private void removeTimeout()
{
ArrayList<K> key = new ArrayList<K>(100); // 得到所有超时的key
for (Map.Entry<K, V> entry : this.entrySet())
{
V value = entry.getValue();
if (value instanceof RequestControl)
{
RequestControl control = (RequestControl) value;
if (control.isTimeOut())
{
key.add(entry.getKey());
}
}
} // 删除对应的control
for (K k : key)
{
this.remove(k);
}
}
}
}
/**
* @author Aray Chou
* Email: Aray(dot)Chou(dot)CN(at)gmail(dot)com
* Replace "(dot)" with "." and replace "(at)" with "@"
*/
package com.aray.core.filter;import com.aray.core.common.Constants;/**
* 请求控制队列。每有一个请求,移出队列过期的时间戳,然后往此队列里加入当前时间戳.
* 如果队列已满,则认为超出请求控制的频度要求。
* <p>
* 算法:
* <ul>
* <li>用一个定长数组存储数据,first指向第一个元素。size表示总元素过数。</li>
* <li>追加数据时候,有可能发生first+size>data.length的情况。这个时候,折回从数组开始插入数据</li>
* </ul>
* </p>
*/
public class RuquestControlQueue
{
/** 第一个元素的下标 */
protected int first; /** 队列的长度,总元素个数 */
protected int size; /** 队列的元素 */
protected long[] data; /**
* @param length
* 队列的长度
*/
public RuquestControlQueue(int length)
{
data = new long[length];
} /**
* 移出过期数据,追加新的时间戳。
*
* @return 如果队列已满,则追加失败,返回false.
*/
public boolean appendCurentTime()
{
this.removeExpired();
return this.append(System.currentTimeMillis());
} /**
* 追加数据
*
* @param value
* @return 队列满,这追加失败,返回false
*/
public synchronized boolean append(long value)
{
if (size == data.length)
return false; int position = (first + size) % data.length;
data[position] = value;
size++; return true; } /**
* 重置队列,清空里面的数据
*/
public synchronized void reset()
{
this.first = 0;
this.size = 0;
} /**
* 删除 {@link com.aray.core.common.Constants.Constants.REQUEST_CONTROL_PERIOD}以前的过期数据。<br />
*/
private void removeExpired()
{
long expired = System.currentTimeMillis() - Constants.REQUEST_CONTROL_PERIOD; // 删除过期的元素
this.removeLess(expired);
} /**
* 移除小于等于value的数据
*
* @param value
*/
public synchronized void removeLess(long value)
{
// 删除过期的元素
if (this.size > 0)
{
int p = this.find(value, this.first, this.size);
if (p != -1)
{
// 第一个元素指针指向p后的元素,移除下标p及其以前的数组元素
int newStart = (p + 1) % this.data.length;
// 修改元素个数
this.size = this.size - (newStart + this.data.length - this.first) % this.data.length;
this.first = newStart;
}
}
} public static void main(String[] args)
{
RuquestControlQueue q = new RuquestControlQueue(20);
q.first = 19;
for (int i = 1; i < 14; i++)
q.append(i); for (int i = 0; i < q.data.length; i++)
{
System.out.print(q.data[i]);
if (i == q.first)
System.out.print('*');
System.out.print(' ');
}
int xxx = 12;
System.out.println("\n" + q.find(xxx));
q.out();
q.removeLess(xxx);
q.out(); } /**
* 在当前队列中,查找小于等于value的最后一个数据
*
* @param value
* @return 小于等于value的最后一个数据的下标
*/
protected int find(long value)
{
return this.find(value, this.first, this.size);
} /**
* 折半查找,从数组position开始的size个数据中,查找最后一个小于等于value的元素
*
* @param value
* @param position
* 开始位置
* @param size
* @return 最后一个小于等于value的元素的下标
*/
protected int find(long value, int position, int size)
{
if (this.size == 0 || this.data[this.first] > value /* value比第一个还小 */)
return -1; // value比最后一个值还大
int lastPosition = (this.first + this.size - 1) % this.data.length;
if (this.data[lastPosition] <= value)
return lastPosition; if (size == 1)
{
if (this.data[position] <= value)
return position;
else
return -1;
} int half = size / 2;
int halfPosition = (position + half) % this.data.length;
if (this.data[halfPosition] > value)
return find(value, position, half);
else
return find(value, halfPosition, size - half);
} /**
* 输出队列,测使用
*/
protected void out()
{
for (int i = 0; i < this.size; i++)
{
int p = (this.first + i) % this.data.length;
System.out.print(this.data[p] + " ");
}
System.out.println();
}
}
ADSL重新拨号换IP,如果换IP都不行,清空IE缓存,cookie这些试验下。