吐槽
前两天一个线上的IP地址库除了点幺蛾子,一查代码,发现用的库早就不更新了,遂决定换库,有几个方案:
纯真数据库是大码农的福音,免费,但是精度一般;IPIP有收费和免费版,免费版不定期更新,收费版精度高,有保障;GeoIP也是收费和免费版,免费版国内的城市精度一般,收费版比较精确,数据比较有特色,还同时提供了经纬度信息。
代码
纯真的数据在国家和省一级的数据还算精确,省下区域的精度不是特别的好,但胜在定期更新,完全免费,将下好的数据库转换为txt格式,并命名为ip.txt(有同学问我在哪现在,这个问题问的好,http://update.cz88.net/soft/setup.zip ,拿去不谢),数据到手,这里截取部分数据:
0.0.0.0 0.255.255.255 IANA 保留地址
1.0.0.0 1.0.0.0 美国 亚太互联网络信息中心(CloudFlare节点)
1.0.0.1 1.0.0.1 美国 APNIC&CloudFlare公共DNS服务器
1.0.0.2 1.0.0.255 美国 亚太互联网络信息中心(CloudFlare节点)
1.0.1.0 1.0.3.255 福建省 电信
1.0.4.0 1.0.7.255 澳大利亚 墨尔本Goldenit有限公司
很明显,第一列是起始IP、第二列是截止IP、第三列是地区、第四列是运营商信息,那么该如何查询呢,代码如下:
public class IPCore
{
private static string IP_PATH ="ip.txt"; //数据文件地址
private const string UnknowIP = "未知地址";
private static Dictionary<int, List<IPInfo>> _ipCols = new Dictionary<int, List<IPInfo>>();
/// <summary>
/// 初始化数据。
/// </summary>
public static void Init()
{
try
{
if (_ipCols != null)
_ipCols.Clear();
using (var sr = new StreamReader(IP_PATH, Encoding.Default))
{
string curLine;
while (!string.IsNullOrEmpty(curLine = sr.ReadLine()))
{
string[] ipAddr = Regex.Split(curLine, "[\\s]+", RegexOptions.None);
if (ipAddr.Length < 3)
continue;
var startIP = ipAddr[0].Split('.');
var endIP = ipAddr[1].Split('.');
var ipAddress = UnknowIP;
if (ipAddr.Length == 4)
{
ipAddress = ipAddr[2];
}
IPInfo ipInfo = new IPInfo();
ipInfo.StartIP = Convert.ToUInt32(startIP[0]) * 1677216 + Convert.ToUInt32(startIP[1]) * 65536 + Convert.ToUInt32(startIP[2]) * 256 + Convert.ToUInt32(startIP[3]);
ipInfo.EndIP = Convert.ToUInt32(endIP[0]) * 1677216 + Convert.ToUInt32(endIP[1]) * 65536 + Convert.ToUInt32(endIP[2]) * 256 + Convert.ToUInt32(endIP[3]);
ipInfo.IpAddress = ipAddress;
int indexIP1 = Convert.ToInt32(startIP[0]);
int indexIP2 = Convert.ToInt32(endIP[0]);
for (int i = indexIP1; i <= indexIP2; i++)
{
if (!_ipCols.ContainsKey(i))
{
List<IPInfo> ipInfoList = new List<IPInfo>();
ipInfoList.Add(ipInfo);
_ipCols.Add(i, ipInfoList);
}
else
{
List<IPInfo> ipInfoList = _ipCols[i];
ipInfoList.Add(ipInfo);
}
}
}
}
//集合构建完成后对IP进行排序
foreach (var key in _ipCols.Keys)
{
_ipCols[key] = _ipCols[key].OrderBy(p => p.StartIP).ToList();
}
}
catch (Exception ex)
{
//Log
}
}
/// <summary>
/// 获取IP地址。
/// </summary>
public static string GetIPAddress(string ip)
{
string[] addressIP = ip.Split('.');
//计算ip对应long值
long ipValue = Convert.ToUInt32(addressIP[0]) * 1677216 + Convert.ToUInt32(addressIP[1]) * 65536 + Convert.ToUInt32(addressIP[2]) * 256 + Convert.ToUInt32(addressIP[3]);
int ipIndex = Convert.ToInt32(addressIP[0]);
var ipInfos = _ipCols[ipIndex];
int high = ipInfos.Count;
for (int low = 0; low <= high;)
{
var point_index = (high + low) / 2;
var ipInfo = ipInfos[point_index];
if (ipValue < ipInfo.StartIP)
{
high = point_index - 1;
continue;
}
else if (ipValue > ipInfo.EndIP)
{
low = point_index + 1;
continue;
}
return ipInfo.IpAddress;
}
return UnknowIP;
}
}
public class IPInfo
{
public long StartIP { get; set; }
public long EndIP { get; set; }
public string IpAddress { get; set; }
}