我想知道如何在Java中限制每个客户端(每个特定IP)的TCP请求。例如,我想为每个客户端IP允许每Y秒最多X个请求。我想过将静态Timer / TimerTask与临时受限IP的HashSet结合使用。
private static final Set<InetAddress> restrictedIPs = Collections.synchronizedSet(new HashSet<InetAddress>());
private static final Timer restrictTimer = new Timer();
因此,当用户连接到服务器时,我将他的IP添加到受限列表中,并启动任务以在X秒内取消限制。
restrictedIPs.add(socket.getInetAddress());
restrictTimer.schedule(new TimerTask()
{
public void run()
{
restrictedIPs.remove(socket.getInetAddress());
}
}, MIN_REQUEST_INTERVAL);
我的问题是,在任务运行时,套接字对象可能会关闭,远程IP地址将无法访问...
欢迎任何想法!此外,如果有人知道Java框架内置的方法来实现这一点,我真的很想听听它。
答案 0 :(得分:3)
一种选择是使用netfilter来实现这一目标。不是'纯'java,但可能是最强大和无错误的解决方案。此示例取自debian-administration
iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent \
--set
iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent \
--update --seconds 60 --hitcount 4 -j DROP
编辑:
只需快速修复代码,保存IP地址并在阻止之前添加计数,即(伪):
IPaddress addr = socket.getAddress();
int hitcount = hitcountMap.get(addr).value();
if (hitcount <= HIT_MAX) {
//only increase if person hasn't reached roof, prevents 'overblocking'
hitcountMap.get(addr).increase();
unblockTimer.schedule(hitcountMap.get(addr).decrease(), BLOCK_TIMEOUT);
}
if (hitcount > HIT_MAX) {
connection.drop();
}
这应该使块最后保持最大BLOCK_TIMEOUT(不保证无bug)。您应该考虑使用信号量进行计数,因为您(可能)会从许多线程运行此代码,具体取决于您的线程模型。
答案 1 :(得分:1)
一个简单的解决方案是:
final InetAddress ip = socket.getInetAddress();
restrictedIPs.add(ip);
restrictTimer.schedule(new TimerTask()
{
public void run()
{
restrictedIPs.remove(ip);
}
}, MIN_REQUEST_INTERVAL);
此方法的问题是需要额外的线程才能删除受限制的IP地址。也许将InetAddress的Map保存到时间戳更容易,以便跟踪他们上次访问页面的时间。这样,您可以在每次客户端启动请求时检查此时间戳。