Как сохранить список IP-адреса в Списке C# для создания этого доступным для поиска для подсетей также?

Если Вы используете Visual C++, используете ключевое слово переопределения каждый раз, когда Вы переопределяете метод базового класса. Таким образом, если кто-либо когда-нибудь, оказывается, изменяет подпись базового класса, она бросит ошибку компилятора, а не неправильный тихо называемый метод. Это сохранило бы меня несколько раз, если бы это существовало ранее.

Пример:

class Foo
{
   virtual void DoSomething();
}

class Bar: public Foo
{
   void DoSomething() override { /* do something */ }
}

6
задан GrZeCh 6 September 2009 в 20:04
поделиться

5 ответов

В конце этого ответа вы найдете полную реализацию структуры для представления адреса IPV4.

Вот действительно простой пример использования: -

List<IPV4Address> list = new List<IPV4Address>();
list.Add(IPV4Address.FromString("3.4.0.0", 24));
var x = IPV4Address.FromString("3.4.0.6");
foreach (var addr in list.Where(a => a.Contains(x)))
  Console.WriteLine(addr);

Значение «3.4 .0.0 / 255.255.255.0 "отображается в консоли, поскольку 3.4.0.6 находится в подсети 3.4.0.0/24. Предполагая, что список заполнен различными подсетями и x может содержать любой адрес, тогда это: -

var result = list.Where(a => a.Contains(x))
    .OrderByDescending(a => a.Mask)
    .FirstOrDefault();

выберет наиболее конкретную подсеть, содержащую x .

public struct IPV4Address
{
  private UInt32 _Value;
  private UInt32 _Mask;

  public UInt32 Value
  {
    get { return _Value; }
    private set { _Value = value; }
  }

  public UInt32 Mask
  {
    get { return _Mask; }
    private set { _Mask = value; }
  }

  public static IPV4Address FromString(string address)
  {
    return FromString(address, 32);
  }

  public static IPV4Address FromString(string address, int maskLength)
  {
    string[] parts = address.Split('.');
    UInt32 value = ((UInt32.Parse(parts[0]) << 24) +
      ((UInt32.Parse(parts[1])) << 16) +
      ((UInt32.Parse(parts[2])) << 8) +
      UInt32.Parse(parts[3]));

    return new IPV4Address(value, maskLength);
  }

  public IPV4Address(UInt32 value)
  {
    _Value = value;
    _Mask = int.MaxValue;
  }

  public IPV4Address(UInt32 value, int maskLength)
  {
    if (maskLength < 0 || maskLength > 32)
      throw new ArgumentOutOfRangeException("maskLength", "Must be 0 to 32");

    _Value = value;
    if (maskLength == 32)
      _Mask = UInt32.MaxValue;
    else
      _Mask = ~(UInt32)((1 << (32 - maskLength))-1);

    if ((_Value & _Mask) != _Value)
      throw new ArgumentException("Address value must be contained in mask");
  }

  public bool Contains(IPV4Address address)
  {
    if ((Mask & address.Mask) == Mask)
    {
      return (address.Value & Mask) == Value;
    }
    return false;
  }

  public override string ToString()
  {
    string result = String.Format("{0}.{1}.{2}.{3}", (_Value >> 24), 
      (_Value >> 16) & 0xFF, 
      (_Value >> 8) & 0xFF, 
      _Value & 0xFF);

    if (_Mask != UInt32.MaxValue)
      result += "/" + String.Format("{0}.{1}.{2}.{3}", (_Mask >> 24),
      (_Mask >> 16) & 0xFF,
      (_Mask >> 8) & 0xFF,
      _Mask & 0xFF);

    return result;
  }
}
4
ответ дан 17 December 2019 в 07:07
поделиться

Определите класс, в котором хранится IP-адрес и длину префикса:

public class IPAddressWithPrefixLength
{
    public IPAddress IPAddress { get; }
    public int PrefixLength { get; }
}

Затем переопределите Equals и GetHashCode таким образом, чтобы принимаются во внимание только первые PrefixLength биты IPAddress.GetAddressBytes () (и, конечно, тип IPAddress).

Затем вы можете использовать этот класс для хранения подсети префиксы в List или использовать их в качестве ключей Dictionary :

var subnets = new List<IPAddressWithPrefixLength>
{
    new IPAddressWithPrefixLength(IPAddress.Parse("1.2.3.4"), 32),
    new IPAddressWithPrefixLength(IPAddress.Parse("3.4.0.0"), 16),
};

var ipawpl = new IPAddressWithPrefixLength(IPAddress.Parse("3.4.5.6"), 16);

Console.WriteLine(subnets.Contains(ipawpl)); // prints "True"

Это также работает с адресами IPv6.

1
ответ дан 17 December 2019 в 07:07
поделиться

Я мог бы использовать двоичное дерево с булевыми метками на узлах. Используя стандартную нотацию, в которой 0 - левый дочерний элемент, а 1 - правый дочерний элемент, 1.2.3.4 будет сохранен путем помещения истины в 00000001000000100000001100000100 (двоичное представление этого адреса) в tree - и false на всех узлах между корнем и this. И наоборот, 3.4.0.0/16 будет сохранен с истиной в 0000001100000100 (первые 16 бит двоичного представления 3.4.0.0).

Когда вам дается адрес для проверки, просто спуститесь вниз по дереву в соответствии с битами этого адреса: если вы достигнете узла с true , адрес будет в списке. Если вы дойдете до конца ветки, адрес отсутствует в списке.

Например, при поиске 3.4.123.48 вы: d спуститься на 16 уровней в дереве до достижения истины, что означает, что этот адрес находится в списке. Но поискав 129.199.195.13, вы узнаете по первому 1 биту в этом адресе, что он не является частью списка.

Я не уверен, насколько важно для вас использовать список введите для хранения этих адресов, так что это может не помочь; OTOH, после того как вы реализовали базовое двоичное дерево с метками, оно должно иметь лучшие асимптотические характеристики производительности, чем .Net List .

так что это может не помочь; OTOH, как только вы реализовали базовое двоичное дерево с метками, оно должно иметь лучшие асимптотические характеристики производительности, чем .Net List .

так что это может не помочь; OTOH, как только вы реализовали базовое двоичное дерево с метками, оно должно иметь лучшие асимптотические характеристики производительности, чем .Net List .

0
ответ дан 17 December 2019 в 07:07
поделиться

Я бы предпочел создать специализированную структуру (класс) для хранения всей этой информации вместе. Возможно, в ближайшем будущем вы захотите расширить его для хранения ipv6 рядом с ipv4 и, возможно, еще каких-то данных (метрика, шлюз и т. Д.).

0
ответ дан 17 December 2019 в 07:07
поделиться

Не храните его в списке - сохраните его в такой структуре, как словарь, где ключ - это IP-адрес, а значение - адрес подсети.

-1
ответ дан 17 December 2019 в 07:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: