⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unitqueryip.pas

📁 delphi,利用"纯真IP数据库"进行IP地理位置查询
💻 PAS
字号:
unit UnitQueryIP;

interface

uses Forms, Windows, Classes, SysUtils, WinSock;

const
  DEFAULT_IPFILENAME = 'IPWry.dat';
  INDEX_SIZE = 7;

type
  TQueryIP = class
  private
    IpDataFile: TFileStream;
    IndexStart: Cardinal;
    IndexEnd: Cardinal;
    function ReadByte(Offset: Cardinal; Num: integer): Cardinal;
    function ReadStr(Offset: Cardinal): String;
  public
    constructor Create(IpDataBase: string);
    function QueryIP(aIP: Cardinal): string; overload;
    function QueryIP(aIP: String): string; overload;
  end;
  function IPQuery: TQueryIP;

implementation

var IPCache: TStringList;
    _IPQuery: TQueryIP = nil;

function IPQuery: TQueryIP;
begin
  if not Assigned(_IPQuery) then
		_IPQuery := TQueryIP.Create(ExtractFilePath(ParamStr(0)) + 'IPWry.dat');
  Result := _IPQuery;
end;

constructor TQueryIP.Create(IpDataBase: string);
begin
  if not FileExists(IpDataBase) then
  begin
    IpDataBase := ExtractFilePath(Application.ExeName)+IpDataBase;
    if not FileExists(IpDataBase) then
      IpDataBase := ExtractFilePath(Application.ExeName)+DEFAULT_IPFILENAME;
  end;

  try
    IpDataFile := TFileStream.Create(IpDataBase, fmOpenRead or fmShareDenyWrite);
  except
    IpDataFile := nil;
  end;

  if IpDataFile<>nil then
  begin
    IndexStart := ReadByte(0, 4);
    IndexEnd := ReadByte(4, 4);
  end else
  begin
    IndexStart := 0;
    IndexEnd := 0;
  end;
end;

function TQueryIP.QueryIP(aIP: Cardinal): string;
var StartPos, EndPos, Middle, ResultRecordPos: Cardinal;
    IndexIP: Cardinal;
    EndIP, RedirectMode: Cardinal;
    CountryPos, AreaPos: Cardinal;
    Country, Area: string;
    addr: in_addr;
begin
  Result := '非法IP格式';
  if integer(aIP)=-1 then
    exit;
  if IpDataFile=nil then
    exit;

  StartPos := IndexStart;
  EndPos := IndexEnd;
  ResultRecordPos := 0;

  while ResultRecordPos=0 do
  begin
    Middle := StartPos + (((EndPos - StartPos) div INDEX_SIZE) div 2) * INDEX_SIZE;
    if (Middle=StartPos) then
    begin
      IndexIP := ReadByte(EndPos, 4);
      if IndexIP<=aIP then
        ResultRecordPos := ReadByte(EndPos+4, 3)
      else
        ResultRecordPos := ReadByte(StartPos+4, 3);
      break;
    end;

    IndexIP := ReadByte(Middle, 4);
    if IndexIP = aIP then
    begin
      ResultRecordPos := ReadByte(Middle+4, 3);
      break;
    end else
    begin
      if IndexIP>aIP then
        EndPos := Middle
      else
        StartPos := Middle;
    end;
  end;

  if ResultRecordPos=0 then
    exit;
  EndIP := ReadByte(ResultRecordPos, 4);
  if aIP>EndIP then
    exit;

  RedirectMode := ReadByte(ResultRecordPos+4, 1);
  if (RedirectMode<>1) and (RedirectMode<>2) then
  begin
    Country := ReadStr(ResultRecordPos+4);
    Area := ReadStr(IpDataFile.Position);
  end else
  if RedirectMode=1 then
  begin
    CountryPos := ReadByte(ResultRecordPos+5, 3);
    RedirectMode := ReadByte(CountryPos, 1);        // 国家重定向模式
    if (RedirectMode<>1) and (RedirectMode<>2) then
    begin
      Country := ReadStr(CountryPos);
      AreaPos := IpDataFile.Position;
      RedirectMode := ReadByte(AreaPos, 1);        // 地区重定向模式
      if (RedirectMode<>1) and (RedirectMode<>2) then
      begin
        Area := ReadStr(AreaPos);
      end else
      begin
        AreaPos := ReadByte(AreaPos+1, 3);; // 地区信息字符串地址
        Area := ReadStr(AreaPos);
      end;
    end else
    begin
      AreaPos := CountryPos+4;
      CountryPos := ReadByte(CountryPos+1, 3); // 国家信息字符串地址
      Country := ReadStr(CountryPos);
      RedirectMode := ReadByte(AreaPos, 1);      // 地区重定向模式
      if (RedirectMode<>1) and (RedirectMode<>2) then
      begin
        Area := ReadStr(AreaPos);
      end else
      begin
        AreaPos := ReadByte(AreaPos+1, 3);; // 地区信息字符串地址
        Area := ReadStr(AreaPos);
      end;
    end;
  end else
  if RedirectMode=2 then
  begin
    CountryPos := ReadByte(IpDataFile.Position, 3); // 国家信息字符串地址
    ResultRecordPos := IpDataFile.Position;
    RedirectMode := ReadByte(ResultRecordPos, 1);  // 地区信息重定向模式
    Country := ReadStr(CountryPos);
    if (RedirectMode<>1) and (RedirectMode<>2) then
    begin
      AreaPos := ResultRecordPos; // 地区信息字符串地址
      Area := ReadStr(AreaPos);
    end else
    begin
      AreaPos := ReadByte(ResultRecordPos+1, 3);; // 地区信息字符串地址
      Area := ReadStr(AreaPos);
    end;
  end;

  if Country='IANA' then
    Result := '未知IP'
  else
  if Country='局域网' then
  begin
    addr.S_addr := ntohl(aIP);
    Result := '同局域网内 IP:'+inet_ntoa(addr);
  end
  else
  begin
    if Area = '' then
      Result := Country
    else
      Result := Country + ' ' + Area;
  end;
end;

// 从指定偏移处读出Num字节的数据
function TQueryIP.QueryIP(aIP: String): string;
begin
  Result := QueryIP(htonl(inet_addr(PChar(aIP))));
end;

function TQueryIP.ReadByte(Offset: Cardinal; Num: integer): Cardinal;
var Buf: Cardinal;
    I: integer;
begin
  Result := 0;
  if IpDataFile=nil then
    exit;
  IpDataFile.Position := Offset;
  for I := 0 to Num - 1 do
  begin
    IpDataFile.ReadBuffer(Buf, 1);
    Result := (Buf shl (I*8)) or Result;
  end;
end;

// 从指定偏移处读出以0为结尾的字符串
function TQueryIP.ReadStr(Offset: Cardinal): String;
var Buf: char;
begin
  Result := '';
  if Offset<20 then
    exit;
  if IpDataFile=nil then
    exit;
  IpDataFile.Position := Offset;
  repeat
    if IpDataFile.Read(Buf, 1)<=0 then
      break;
    if Buf=char(0) then
      break;
    Result := Result + Buf;
  until False;
end;

initialization
  _IPQuery := TQueryIP.Create(ExtractFilePath(ParamStr(0)) + 'IPWry.dat');

finalization
  _IPQuery.Free;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -