2009-09-06 10 views
6

मुझे उन पते के साथ आईपी एड्रेस सूची को सही ढंग से कैसे स्टोर करना चाहिए जो इसे खोजने योग्य बनाने के लिए सबनेट हैं?सी # सूची में आईपी एड्रेस सूची को स्टोर करने के लिए कैसे इसे सबनेट्स के लिए खोजने योग्य बनाने के लिए?

दो उदाहरण हैं:

  1. मैं आईपी पते 1.2.3.4 और मेरी सी # सूची में 1.2.3.4 प्रविष्टि इसलिए यहाँ हम कोई समस्या नहीं है।

  2. मेरे पास आईपी पता 3.4.5.6 है और मेरे सी # सूची में मेरे पास सबनेट 3.4.0.0/24 है। मेरी समस्या यहाँ है।

दूसरे उदाहरण को कवर करने के लिए सूची में आईपी सबनेट कैसे स्टोर करें? इस तरह के बजाय एक शब्दकोश, जहां कुंजी IP पता है के रूप में एक संरचना में संग्रहीत है, और मूल्य सबनेट पता है -

धन्यवाद

उत्तर

4

इस उत्तर के अंत में आपको आईपीवी 4 पते का प्रतिनिधित्व करने के लिए संरचना का पूर्ण कार्यान्वयन मिलेगा।

यहाँ वास्तव में उपयोग के सरल उदाहरण है: -

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 के बाद से सांत्वना inthe प्रदर्शित किया जाता है 3.4.0.0/24 सबनेट में पाया जाता है। मान लिया जाये कि list विभिन्न सबनेट से भरा हुआ है और 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; 
    } 
} 
-1

एक सूची में संग्रहीत नहीं।

0

मैं इन सभी जानकारी को एकसाथ स्टोर करने के लिए एक विशेष संरचना (कक्षा) बनाना पसंद करूंगा। शायद निकट भविष्य में आप इसे ipv4 के पास ipv6 स्टोर करने के लिए विस्तारित करना चाहते हैं, और शायद कुछ और डेटा (मीट्रिक, गेटवे, आदि)।

1

एक वर्ग है कि एक IPAddress और उपसर्ग लंबाई संग्रहीत करता है परिभाषित करें:

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

फिर Equals और GetHashCode ऐसी है कि केवल पहले PrefixLengthIPAddress.GetAddressBytes() के टुकड़े को ध्यान में रखा जाता है (और, ज़ाहिर है, IPAddress प्रकार ओवरराइड)।

फिर आप एक List<T> में सबनेट उपसर्गों स्टोर करने के लिए इस वर्ग का उपयोग करें या एक Dictionary<K,V> की कुंजी के रूप में उपयोग कर सकते हैं: भी,

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 पते के साथ काम करता है।

+0

+1, लेकिन ipawpl के निर्माता को 32 की उपसर्ग लंबाई का उपयोग नहीं करना चाहिए? आदर्श रूप से, IPAddressWithPrefixLength (IPAddress.Parse ("3.4.5.6"), 32) के साथ निर्मित एक उदाहरण भी पाया जाना चाहिए, है ना? –

+0

@ विनी: मुझे ऐसा नहीं लगता है, क्योंकि 3.4.5.6 में उपसर्ग की लंबाई अभी भी 16 बिट्स है, नहीं? (या 24?) – dtb

+0

@ डीटीबी: मेरा मतलब था, नेटवर्क पता (16-बिट उपसर्ग के साथ) सबनेट में एक मनमाना पते से मेल खाना चाहिए (जो एक पूर्ण 32-बिट पता हो सकता है, या 24-बिट कह सकता है मूल 3.4.0.0 नेटवर्क का सबनेट)। –

0

मैं नोड्स पर बूलियन लेबल के साथ एक बाइनरी पेड़ का उपयोग कर सकता था। मानक नोटेशन का उपयोग जिसमें 0 बाएं बच्चे और 1 सही बच्चा है, 1.2.3.4 पेड़ में 00000001000000100000001100000100 (उस पते का बाइनरी प्रतिनिधित्व) पर true डालकर संग्रहीत किया जाएगा - और रूट के बीच सभी नोड्स पर झूठा । इसके विपरीत, 3.4.0.0/16 true0000001100000100 (3.4.0.0 के द्विआधारी प्रतिनिधित्व के पहले 16 बिट्स) के साथ संग्रहीत किया जाएगा।

जब आपको परीक्षण करने के लिए पता दिया जाता है, तो उस पते के बिट्स के अनुसार पेड़ नीचे जाएं: यदि आप true नोड तक पहुंचते हैं, तो पता सूची में है। यदि आप किसी शाखा के अंत तक पहुंचते हैं, तो पता सूची में नहीं है।

उदाहरण के लिए, यदि 3.4.123.48 को देख रहे हैं, तो आप सत्य तक पहुंचने से पहले पेड़ में 16 स्तर नीचे जायेंगे, जिसका अर्थ है कि यह पता सूची में है। लेकिन 12 9 .1 99 .195.13 को देखकर, आप उस पते में पहले 1 बिट से जान लेंगे कि यह सूची का हिस्सा नहीं है।

मुझे यकीन नहीं है कि List का उपयोग उन पते को स्टोर करने के लिए आपके लिए कितना महत्वपूर्ण है, इसलिए इससे मदद नहीं मिल सकती है; ओटीओएच, एक बार जब आप लेबल्स के साथ एक मूल बाइनरी पेड़ लागू कर लेते हैं, तो इसमें .NET List की तुलना में बेहतर एसिम्प्टोटिक प्रदर्शन विशेषताओं होनी चाहिए।