/// <summary> /// 从IP文件中读取指定字节并转换位long /// </summary> /// <param name="stream"></param> /// <param name="bytesCount">需要转换的字节数,主意不要超过8字节</param> /// <returns></returns> private long ReadLongX(IpDbAccessor stream, int bytesCount) { var bytes = new byte[8]; stream.Read(bytes, 0, bytesCount); return(BitConverter.ToInt64(bytes, 0)); }
///<summary> ///查找IP地址所在的绝对偏移量 ///</summary> ///<param name="ip"></param> ///<returns></returns> private long locateIP(IpDbAccessor ipFile, byte[] ip) { long m = 0; int r; var b4 = new byte[4]; //比较第一个IP项 readIP(ipFile, _startPosition, b4); r = compareIP(ip, b4); if (r == 0) { return(_startPosition); } else if (r < 0) { return(-1); } //开始二分搜索 for (long i = _startPosition, j = _endPosition; i < j;) { m = this.getMiddleOffset(i, j); readIP(ipFile, m, b4); r = compareIP(ip, b4); if (r > 0) { i = m; } else if (r < 0) { if (m == j) { j -= IP_RECORD_LENGTH; m = j; } else { j = m; } } else { ipFile.Position = m + 4; return(ReadLongX(ipFile, 3));//readLong3(m + 4); } } ipFile.Position = m + 4; m = ReadLongX(ipFile, 3);//readLong3(m + 4); readIP(ipFile, m, b4); r = compareIP(ip, b4); if (r <= 0) { return(m); } else { return(-1); } }
///<summary> ///从当前位置读取3字节 ///</summary> ///<returns></returns> private long readLong3(IpDbAccessor ipFile) { long ret = 0; ret |= Convert.ToInt64(ipFile.ReadByte() & 0xFF); ret |= Convert.ToInt64((ipFile.ReadByte() << 8) & 0xFF00); ret |= Convert.ToInt64((ipFile.ReadByte() << 16) & 0xFF0000); return(ret); }
///<summary> ///根据当前位置,读取3字节 ///</summary> ///<param name="offset"></param> ///<returns></returns> private long readLong3(IpDbAccessor ipFile, long offset) { long ret = 0; ipFile.Position = offset; ret |= Convert.ToInt64(ipFile.ReadByte() & 0xFF); ret |= Convert.ToInt64((ipFile.ReadByte() << 8) & 0xFF00); ret |= Convert.ToInt64((ipFile.ReadByte() << 16) & 0xFF0000); return(ret); }
///<summary> ///从当前位置读取四字节,此四字节是IP地址 ///</summary> ///<param name="offset"></param> ///<param name="ip"></param> private void readIP(IpDbAccessor ipFile, long offset, byte[] ip) { ipFile.Position = offset; ipFile.Read(ip, 0, ip.Length); byte tmp = ip[0]; ip[0] = ip[3]; ip[3] = tmp; tmp = ip[1]; ip[1] = ip[2]; ip[2] = tmp; }
/// <inheritdoc /> /// <summary> /// 初始化 /// </summary> /// <param name="token"></param> /// <returns></returns> public virtual async Task <bool> InitAsync(bool getNewDb = false, CancellationToken token = default(CancellationToken)) { if (_init != null && !getNewDb) { return(_init.Value); } await _initLock.WaitAsync(token); try { if (_init != null && !getNewDb) { return(_init.Value); } var isExist = DbFileExist(_qqwryOptions.DbPath); if (!isExist || getNewDb) { await UpdateDbAsync(); } #if DEBUG System.Diagnostics.Debug.WriteLine("使用IP数据库{0}", _qqwryOptions.DbPath); #endif _qqwryDbBytes = FileToBytes(_qqwryOptions.DbPath); var ipFile = new IpDbAccessor(_qqwryDbBytes); _startPosition = ReadLongX(ipFile, 4); _endPosition = ReadLongX(ipFile, 4); //总记录数 _ipCount = Convert.ToInt32((_endPosition - _startPosition) / IP_RECORD_LENGTH + 1); _version = null; _init = true; } finally { _initLock.Release(); } if (_qqwryDbBytes == null) { throw new InvalidOperationException("无法打开IP数据库" + _qqwryOptions.DbPath + "!"); } return(true); }
/// <inheritdoc /> /// <summary> /// 初始化 /// </summary> /// <returns></returns> public virtual bool Init(bool getNewDb = false) { if (_init != null && !getNewDb) { return(_init.Value); } _initLock.Wait(); try { if (_init != null && !getNewDb) { return(_init.Value); } var isExist = DbFileExist(_qqwryOptions.DbPath); if (!isExist || getNewDb) { UpdateDb(); } #if DEBUG System.Diagnostics.Debug.WriteLine(format: $"使用IP数据库{_qqwryOptions.DbPath}"); #endif _qqwryDbBytes = FileToBytes(_qqwryOptions.DbPath); var ipFile = new IpDbAccessor(_qqwryDbBytes); _startPosition = ReadLongX(ipFile, 4); _endPosition = ReadLongX(ipFile, 4); //总记录数 _ipCount = Convert.ToInt32((_endPosition - _startPosition) / IP_RECORD_LENGTH + 1); _version = null; _init = true; } finally { _initLock.Release(); } if (_qqwryDbBytes == null) { throw new InvalidOperationException("无法打开IP数据库" + _qqwryOptions.DbPath + "!"); } return(true); }
///<summary> ///取得具体信息 ///</summary> ///<param name="offset"></param> ///<returns></returns> private IpLocation getIPLocation(IpLocation loc, IpDbAccessor ipFile, long offset) { ipFile.Position = offset + 4; //读取第一个字节判断是否是标志字节 byte one = (byte)ipFile.ReadByte(); if (one == REDIRECT_MODE_1) { //第一种模式 //读取国家偏移 long countryOffset = ReadLongX(ipFile, 3);//readLong3(); //转至偏移处 ipFile.Position = countryOffset; //再次检查标志字节 byte b = (byte)ipFile.ReadByte(); if (b == REDIRECT_MODE_2) { loc.Country = readString(ipFile, ReadLongX(ipFile, 3));//readString(readLong3()); ipFile.Position = countryOffset + 4; } else { loc.Country = readString(ipFile, countryOffset); } //读取地区标志 loc.Area = readArea(ipFile, ipFile.Position); } else if (one == REDIRECT_MODE_2) { //第二种模式 loc.Country = readString(ipFile, ReadLongX(ipFile, 3));//readString(readLong3()); loc.Area = readArea(ipFile, offset + 8); } else { //普通模式 loc.Country = readString(ipFile, --ipFile.Position); loc.Area = readString(ipFile, ipFile.Position); } return(loc); }
///<summary> ///读取字符串 ///</summary> ///<param name="offset"></param> ///<returns></returns> private string readString(IpDbAccessor ipFile, long offset) { var buf = new byte[100]; ipFile.Position = offset; int i = 0; for (i = 0, buf[i] = (byte)ipFile.ReadByte(); buf[i] != (byte)(0); buf[++i] = (byte)ipFile.ReadByte()) { ; } if (i > 0) { return(_encodingGb2312.GetString(buf, 0, i)); } else { return(""); } }
///<summary> ///搜索IP地址搜索 ///</summary> ///<param name="ip"></param> ///<returns></returns> public IpLocation ReadLocation(IpLocation loc, string ip) { //将字符IP转换为字节 string[] ipSp = ip.Split('.'); if (ipSp.Length != 4) { throw new ArgumentOutOfRangeException("不是合法的IP地址!"); } byte[] IP = new byte[4]; for (int i = 0; i < IP.Length; i++) { IP[i] = (byte)(int.Parse(ipSp[i]) & 0xFF); } var ipFile = new IpDbAccessor(_qqwryDbBytes); long offset = locateIP(ipFile, IP); if (offset != -1) { loc = getIPLocation(loc, ipFile, offset); } return(loc); }
///<summary> ///读取地区名称 ///</summary> ///<param name="offset"></param> ///<returns></returns> private string readArea(IpDbAccessor ipFile, long offset) { ipFile.Position = offset; byte one = (byte)ipFile.ReadByte(); if (one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2) { ipFile.Position = offset + 1; long areaOffset = ReadLongX(ipFile, 3);//readLong3(offset + 1); if (areaOffset == 0) { return(unArea); } else { return(readString(ipFile, areaOffset).Replace(" CZ88.NET", "")); } } else { return(readString(ipFile, offset).Replace(" CZ88.NET", "")); } }