在产品中可能存在不同客户端,请求同一个服务端接口的场景。

例如小程序和App或者浏览器中,如果需要对请求的归属地进行分析,前提是需要先获取请求所在的国家或城市,这种定位通常需要主动授权,而用户一般是不愿意提供的,就需要通过请求的IP来进行归属地计算。

IP地址一般分为两种,IPV4和IPV6,相应的计算方式也有差异,以国家维度来参考,每个国家都有对应的网段范围,计算网段中的最小和最大IP地址的对应数值,然后对比请求的IP地址,来判断属于哪个国家的网段范围。

import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.util.StrUtil;
import java.math.BigInteger;
import java.net.InetAddress; public class IpCalculate {
public static void main(String[] args) throws Exception {
// IPv4 网段
String ipv4Network = "IPv4 网段";
String[] ipv4Param = StrUtil.splitToArray(ipv4Network, "/"); // IPv4 起始和结束IP
String ipv4StartIp = Ipv4Util.getBeginIpStr(ipv4Param[0],Integer.parseInt(ipv4Param[1]));
String ipv4OverIp = Ipv4Util.getEndIpStr(ipv4Param[0],Integer.parseInt(ipv4Param[1]));
System.out.println(ipv4StartIp);
System.out.println(ipv4OverIp); // IPv4 起始和结束IP对应的Long值
System.out.println(Ipv4Util.ipv4ToLong(ipv4StartIp));
System.out.println(Ipv4Util.ipv4ToLong(ipv4OverIp)); // IPv6 网段
String ipv6Network = "IPv6 网段";
String[] ipv6Param =ipv6Network.split("/");
int prefixLength = Integer.parseInt(ipv6Param[1]); // IPv6 起始和结束IP
InetAddress baseAddress = InetAddress.getByName(ipv6Param[0]);
BigInteger baseValue = new BigInteger(1, baseAddress.getAddress());
BigInteger mask = BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE)
.shiftRight(128 - prefixLength).shiftLeft(128 - prefixLength);
BigInteger minIp = baseValue.and(mask);
BigInteger maxIp = minIp.add(BigInteger.ONE.shiftLeft(128 - prefixLength).subtract(BigInteger.ONE));
System.out.println(toIPv6String(minIp));
System.out.println(toIPv6String(maxIp)); // IPv6 起始和结束IP对应的Long值
System.out.println(minIp);
System.out.println(maxIp);
} private static String toIPv6String(BigInteger value) throws Exception {
byte[] bytes = value.toByteArray();
byte[] ipv6Bytes = new byte[16];
int start = bytes.length > 16 ? bytes.length - 16 : 0;
int length = Math.min(bytes.length, 16);
System.arraycopy(bytes, start, ipv6Bytes, 16 - length, length);
return InetAddress.getByAddress(ipv6Bytes).getHostAddress();
}
}

不过网段地址和国家的对应关系需要进行维护,如果归属地分析不需要非常精准,可以直接使用开源的字典库,比如使用比较多的就是GeoIP2组件。

<dependency>
<groupId>com.maxmind.geoip2groupId>
<artifactId>geoip2</artifactId>
</dependency>

通过组件中提供的API加载相应的文件字典,然后传入IP地址进行归属地判断,这里要注意争议和敏感地区的处理,如果出错产品可不止是上热搜的问题了。

import com.maxmind.geoip2.DatabaseReader;
import java.io.File;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress; public class GeoIpTool {
public static void main(String[] args) throws Exception { // 读取IP库文件
File ipFile = new File("IP文件库");
DatabaseReader reader = new DatabaseReader.Builder(ipFile).build(); // IPV4地址
InetAddress ipV4 = InetAddress.getByName("IPV4");
if (ipV4 instanceof Inet4Address){
System.out.println(reader.country(ipV4));
System.out.println(reader.country(ipV4).getCountry());
// 默认英文名
System.out.println(reader.country(ipV4).getCountry().getName());
// 查询中文名
System.out.println(reader.country(ipV4).getCountry().getNames().get("zh-CN"));
} // IPV6地址
InetAddress ipV6 = InetAddress.getByName("IPV6");
if (ipV6 instanceof Inet6Address){
System.out.println(reader.country(ipV6));
System.out.println(reader.country(ipV6).getCountry());
// 默认英文名
System.out.println(reader.country(ipV6).getCountry().getName());
// 查询中文名
System.out.println(reader.country(ipV6).getCountry().getNames().get("zh-CN"));
}
}
}

如果需要非常精确的实时归属地分析,可以购买专业的IP网段数据,实时更新到本地的数据库中,作为IP字典使用,获取请求的IP后,直接范围匹配即可。

CREATE TABLE `ip_place` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`network` varchar(100) DEFAULT NULL COMMENT '网段区间',
`min_ip` bigint(20) DEFAULT NULL COMMENT '最小IP',
`max_ip` bigint(20) DEFAULT NULL COMMENT '最大IP',
`min_ip_number` bigint(20) DEFAULT NULL COMMENT '最小IP数值',
`max_ip_number` bigint(20) DEFAULT NULL COMMENT '最大IP数值',
`ip_place` varchar(100) DEFAULT NULL COMMENT '归属地',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP归属地';

最后需要补充说一句,对于很多标准的数据,尽可能在项目最初就设计好字典枚举或者数据表,避免后续规范时面临数据清洗的问题。

通过IP计算分析归属地的更多相关文章

  1. TCP、UDP、IP 协议分析

    http://rabbit.xttc.edu.cn/rabbit/htm/artical/201091145609.shtml  http://bhsc881114.github.io/2015/06 ...

  2. TCP、UDP、IP协议分析

    此篇文章的原创作者是:草根老师博客(程姚根) chengyaogen.blog.chinaunix.net 感谢原作者! 互连网早期的时候,主机间的互连使用的是NCP协议.这种协议本身有很多缺陷,如: ...

  3. TCP/IP协议分析

    一;前言 学习过TCP/IP协议的人多有一种感觉,这东西太抽象了,没有什么数据实例,看完不久就忘了.本文将介绍一种直观的学习方法,利用协议分析工具学习TCP/IP,在学习的过程中能直观的看到数据的具体 ...

  4. TCP/IP协议分析(推荐)

    一;前言 学习过TCP/IP协议的人多有一种感觉,这东西太抽象了,没有什么数据实例,看完不久就忘了.本文将介绍一种直观的学习方法,利用协议分析工具学习TCP/IP,在学习的过程中能直观的看到数据的具体 ...

  5. [SuProxy]Ngnix+Lua 实现SSH2,LDAP,ORACLE,SQLSERVER等TCP/IP协议分析,劫持,代理,会话及负载

    目录 目录 目录 前言 介绍 安装 下载并拷贝 使用LuaRocks安装 运行测试 使用简介 处理器(processor)创建 通道(channel)创建 负载均衡 会话信息和会话管理 Event H ...

  6. floating IP 原理分析 - 每天5分钟玩转 OpenStack(107)

    上一节我们通过 Web UI 创建为 cirros-vm3 分配了浮动 IP,今天将分析其工作原理. 首先查看 router 的 interface 配置: 可以看到,floating IP 已经配置 ...

  7. Linux内核TCP/IP参数分析与调优

    转载于:http://www.itxuexiwang.com/a/liunxjishu/2016/0225/167.html?1456482565 如下图展示的是TCP的三个阶段.1,TCP三次握手. ...

  8. C# 根据IP查询地址归属地

    必备文件:IPLocation.dll.QQWry.Dat 下载地址:http://pan.baidu.com/s/1jG1dlOy (可百度下载) 之前有过将 QQWry.Dat 转为 Access ...

  9. tcpdump使用和TCP/IP包分析

    关于tcpdump如何抓包,本文不再总结,可以查看 tcpdump的官方地址查看http://www.tcpdump.org 本文重点记录两个部分:           第一部分:tcpdump所抓包 ...

  10. 软考计算机网络原理之IP计算问题汇总

    转自 http://www.cnblogs.com/jyh317/archive/2013/04/14/3018650.html 1.IP地址 分类: ①A类IP地址 ②B类IP地址 ③C类IP地址 ...

随机推荐

  1. Luogu P4425 转盘 题解 [ 黑 ] [ 线段树 ] [ 贪心 ] [ 递归 ]

    转盘:蒟蒻的第一道黑,这题是贪心和线段树递归合并的综合题. 贪心 破环成链的 trick 自然不用多说. 首先观察题目,很容易发现一个性质:只走一圈的方案一定最优.这个很容易证,因为再绕一圈回来标记前 ...

  2. 零基础使用AI辅助编写易简历小程序的一些心得体会

    春节期间利用了一点时间体验了Copilot开发了一个小程序,先说结论: AI只是AI,并不能取代程序员. 你能做的,AI能做的更快:你不能做的,AI就大概率会糊弄你. 开发小程序的背景就是本身有一个易 ...

  3. ES - 概述

    前言 Q1:ElasticSearch 是什么? 为什么要学习? ElasticSearch 是一个分布式.可扩展.实时的搜索和分析引擎,基于 Lucene 构建.它可以用于全文搜索.结构化搜索.分析 ...

  4. 中国联通校园招聘:软件研究院Offer面经

      本文介绍2024届春招中,中国联通软件研究院广州分院的软件研发岗位的3场面试基本情况.提问问题等.   2024年03月投递了中国联合网络通信有限公司下属软件研究院的软件研发岗位,所在部门为广州分 ...

  5. Echarts与Vue3中获取DOM节点可能出现的异常错误

    useTemplateRef 的简单介绍 官方:返回一个浅层 ref,其值将与模板中的具有匹配 ref attribute 的元素或组件同步. 参数匹配机制‌:useTemplateRe的参数需与模板 ...

  6. 【数值计算方法】线性方程组迭代算法的Python实现

    线性方程组迭代算法的Python实现 jacobi,GS,SOR迭代法 def JacobiIter(A:np.ndarray, b:np.ndarray, tol:float=1e-5, maxIt ...

  7. Vulnhub-Node

    利用信息收集拿到路径得到账户密码,下载备份文件,base64解密后,利用fcrackzip爆破zip压缩包,得到一个文件,查看app.js,发现泄露的账户密码,连接ssh,成功连接,利用ubuntu历 ...

  8. jQuery ajax 文件上传 Request Headers 缺少 boundary

    原文地址: https://blog.jijian.link/2020-07-28/jquery-ajax-upload-file/ 一般上传方式 const file = document.getE ...

  9. hexo 图片添加水印(png, jpeg, jpg, gif)

    文章同步发布:https://blog.jijian.link/2020-04-21/hexo-watermark/ 本文折腾 hexo 图片添加水印功能,大部分代码沿用: nodejs 图片添加水印 ...

  10. .NET周刊【3月第1期 2025-03-02】

    国内文章 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章 https://www.cnblogs.com/shanyou/p/18737657 2025年2月25日,.NET ...