Delphi中的IP地址字符串例程?

时间:2011-12-15 19:10:33

标签: string delphi delphi-7 ip-address

我正在寻找Delphi中验证和操作IP地址的方法。它应该能做的一些事情是......

  • 验证字符串是否为有效的IP地址
  • 验证字符串是否为有效的子网掩码
  • 验证IP地址是否在给定的子网中
  • 用于存储IP地址的某种类型(记录或字符串或其他)
  • IP地址类型的基本转换,例如StringArray[0..3] of Byte
  • 可以使IP操作更容易的任何其他IP地址例程

基本原因是我希望在继续进行并重新发明它们之前,看看这些东西是否已经存在。

2 个答案:

答案 0 :(得分:8)

我曾经写过一个IPv4 and IPv6 conversion unit,包括两种类型IP地址的自定义变体类型。 This answer展示了其功能的一些示例。最初,它被设计为在某些滑块控件 1)上按比例显示各种类型的值。然后要求默认现有的库是不够的,但我同意这里的评论,你可能只会帮助Indy(10!)或类似的。

使用该单元的几个代码段回答您的问题列表:

  • 问题4:IP类型的存储类型:

    const
      IPv4BitSize = SizeOf(Byte) * 4 * 8;
      IPv6BitSize = SizeOf(Word) * 8 * 8;
    
    type
      T4 = 0..3;
      T8 = 0..7;
      TIPv4ByteArray = array[T4] of Byte;
      TIPv6WordArray = array[T8] of Word;
    
      TIPv4 = packed record
        case Integer of
          0: (D, C, B, A: Byte);
          1: (Groups: TIPv4ByteArray);
          2: (Value: Cardinal);
      end;
    
      TIPv6 = packed record
        case Integer of
          0: (H, G, F, E, D, C, B, A: Word);
          1: (Groups: TIPv6WordArray);
      end;
    
  • 问题5:将IP地址字符串转换为这些记录或数组类型:

    function StrToIPv4(const S: String): TIPv4;
    var
      SIP: String;
      Start: Integer;
      I: T4;
      Index: Integer;
      Count: Integer;
      SGroup: String;
      G: Integer;
    begin
      SIP := S + '.';
      Start := 1;
      for I := High(T4) downto Low(T4) do
      begin
        Index := PosEx('.', SIP, Start);
        if Index = 0 then
          IPv4ErrorFmt(SInvalidIPv4Value, S);
        Count := Index - Start + 1;
        SGroup := Copy(SIP, Start, Count - 1);
        if TryStrToInt(SGroup, G) and (G >= Low(Word)) and (G <= High(Word)) then
            Result.Groups[I] := G
          else
            Result.Groups[I] := 0;
        Inc(Start, Count);
      end;
    end;
    
    function StrToIPv6(const S: String): TIPv6;
    { Valid examples for S:
      2001:0db8:85a3:0000:0000:8a2e:0370:7334
      2001:db8:85a3:0:0:8a2e:370:7334
      2001:db8:85a3::8a2e:370:7334
      ::8a2e:370:7334
      2001:db8:85a3::
      ::1
      ::
      ::ffff:c000:280
      ::ffff:192.0.2.128 }
    var
      ZeroPos: Integer;
      DotPos: Integer;
      SIP: String;
      Start: Integer;
      Index: Integer;
      Count: Integer;
      SGroup: String;
      G: Integer;
    
      procedure NormalNotation;
      var
        I: T8;
      begin
        SIP := S + ':';
        Start := 1;
        for I := High(T8) downto Low(T8) do
        begin
          Index := PosEx(':', SIP, Start);
          if Index = 0 then
            IPv6ErrorFmt(SInvalidIPv6Value, S);
          Count := Index - Start + 1;
          SGroup := '$' + Copy(SIP, Start, Count - 1);
          if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
            IPv6ErrorFmt(SInvalidIPv6Value, S);
          Result.Groups[I] := G;
          Inc(Start, Count);
        end;
      end;
    
      procedure CompressedNotation;
      var
        I: T8;
        A: array of Word;
      begin
        SIP := S + ':';
        Start := 1;
        I := High(T8);
        while Start < ZeroPos do
        begin
          Index := PosEx(':', SIP, Start);
          if Index = 0 then
            IPv6ErrorFmt(SInvalidIPv6Value, S);
          Count := Index - Start + 1;
          SGroup := '$' + Copy(SIP, Start, Count - 1);
          if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
            IPv6ErrorFmt(SInvalidIPv6Value, S);
          Result.Groups[I] := G;
          Inc(Start, Count);
          Dec(I);
        end;
        FillChar(Result.H, (I + 1) * SizeOf(Word), 0);
        if ZeroPos < (Length(S) - 1) then
        begin
          SetLength(A, I + 1);
          Start := ZeroPos + 2;
          repeat
            Index := PosEx(':', SIP, Start);
            if Index > 0 then
            begin
              Count := Index - Start + 1;
              SGroup := '$' + Copy(SIP, Start, Count - 1);
              if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
                IPv6ErrorFmt(SInvalidIPv6Value, S);
              A[I] := G;
              Inc(Start, Count);
              Dec(I);
            end;
          until Index = 0;
          Inc(I);
          Count := Length(A) - I;
          Move(A[I], Result.H, Count * SizeOf(Word));
        end;
      end;
    
      procedure DottedQuadNotation;
      var
        I: T4;
      begin
        if UpperCase(Copy(S, ZeroPos + 2, 4)) <> 'FFFF' then
          IPv6ErrorFmt(SInvalidIPv6Value, S);
        FillChar(Result.E, 5 * SizeOf(Word), 0);
        Result.F := $FFFF;
        SIP := S + '.';
        Start := ZeroPos + 7;
        for I := Low(T4) to High(T4) do
        begin
          Index := PosEx('.', SIP, Start);
          if Index = 0 then
            IPv6ErrorFmt(SInvalidIPv6Value, S);
          Count := Index - Start + 1;
          SGroup := Copy(SIP, Start, Count - 1);
          if not TryStrToInt(SGroup, G) or (G > High(Byte)) or (G < 0) then
            IPv6ErrorFmt(SInvalidIPv6Value, S);
          case I of
            0: Result.G := G shl 8;
            1: Inc(Result.G, G);
            2: Result.H := G shl 8;
            3: Inc(Result.H, G);
          end;
          Inc(Start, Count);
        end;
      end;
    
    begin
      ZeroPos := Pos('::', S);
      if ZeroPos = 0 then
        NormalNotation
      else
      begin
        DotPos := Pos('.', S);
        if DotPos = 0 then
          CompressedNotation
        else
          DottedQuadNotation;
      end;
    end;
    

对于Q1到Q3,您必须自己派生一些例程,但 应该没有任何问题。

1)对于那些感兴趣的人,this slider controlthis topic作为此单位的启动。

答案 1 :(得分:3)

我已经编写了您需要的所有功能,但我担心我无法共享代码。

但是,Synapse库在 synaip 单元中包含了不少功能。 e.g。

function IsIP(const Value: string): Boolean;
function IsIP6(const Value: string): Boolean;
function IPToID(Host: string): Ansistring;
function StrToIp6(value: string): TIp6Bytes;
function Ip6ToStr(value: TIp6Bytes): string;
function StrToIp(value: string): integer;
function IpToStr(value: integer): string;
function ReverseIP(Value: AnsiString): AnsiString;
function ReverseIP6(Value: AnsiString): AnsiString;

几年前,当我尝试这些功能时,IPv6功能有点儿麻烦,特别是在处理压缩的IPv6地址时。

如果你想自己动手,请点击几点:

  • 操作IPv4地址非常简单,因为它们只包含 32位,可以存储在标准整数类型中。 IPv6的 地址更难,因为它们需要128位且没有本机类型 那么多位。
  • 在尝试操作IP地址之前,先将其转换为 整数(当然只有IPv4,IPv6需要不同的存储空间 方法)。为此,请使用“。”拆分IP地址。作为分隔符。 检查每个单独的值仅包含数字,并且介于0之间 然后使用这些值生成最终的整数。
  • 将IP地址转换为整数后,即可 你喜欢操纵它。例如,给定一个IP地址和 子网掩码,您可以找到IP地址所属的子网 例如IPtoInt(IPAddress)AND NOT(IPToInt(SubnetMask))=的整数 子网。现在,您可以将整数IP地址与整数进行同步 子网以查看IP是否属于子网。
  • 最后,将整数IP地址转换回字符串。

如果您有任何具体问题,我也可以尝试回答。