使用redis有序集合sorted set设计高效查询ip所在地
1、将纯真版ip数据 xxx.data 导入至 redis(整个过程只花费了几秒)
引入nuget包 CSRedisCore,使用方法见:https://github.com/2881099/csredis
/// <summary> /// 更新ip库,请先将ip库上传至 /data/qqwry.dat,gb2312格式 /// </summary> /// <returns></returns> [HttpPost("update_ip")] public APIReturn 更新ip库() { RedisHelper.Remove("iplib"); var lines = Encoding.GetEncoding("GB2312").GetString(System.IO.File.ReadAllBytes("/data/qqwry.dat")).Split(new string[] { "\r\n" }, StringSplitOptions.None); var lines_index = 0; while(lines_index < lines.Length) { var members = new List<(double, string)>(); for (var b = 0; b < 50000; b++) { try { var ipstart = Lib.Ip2Long(lines[lines_index].Substring(0, 15).Trim()); var ipend = Lib.Ip2Long(lines[lines_index].Substring(16, 15).Trim()); var location = lines[lines_index].Substring(32).Replace("CZ88.NET", "").Trim(); members.Add((ipend, $"{ipstart}-{ipend} {location}")); } catch { } if (++lines_index >= lines.Length) break; } if (members.Count > 0) RedisHelper.ZAdd("iplib", members.ToArray()); } return AR.成功; }
public static long Ip2Long(string ip) { char[] separator = new char[] { '.' }; string[] items = ip.Split(separator); return long.Parse(items[0]) << 24 | long.Parse(items[1]) << 16 | long.Parse(items[2]) << 8 | long.Parse(items[3]); } public static string Long2Ip(long ipInt) { StringBuilder sb = new StringBuilder(); sb.Append((ipInt >> 24) & 0xFF).Append("."); sb.Append((ipInt >> 16) & 0xFF).Append("."); sb.Append((ipInt >> 8) & 0xFF).Append("."); sb.Append(ipInt & 0xFF); return sb.ToString(); }
2、定义根据ip查询所在地的函数(单次查询效率在1ms以内)
public static string GetLocationByIpAddress(string ip) { if (string.IsNullOrEmpty(ip)) return "未知"; var find = RedisHelper.ZRangeByScore("iplib", Lib.Ip2Long(ip), double.MaxValue, 1, 0); if (find.Any()) return find.First().Substring(find.First().IndexOf(' ')); return "未知"; }