Wie konvertiere ich eine IPv4-Adresse in eine Ganzzahl in C #?


99

Ich suche nach einer Funktion, die eine Standard-IPv4-Adresse in eine Ganzzahl konvertiert. Bonuspunkte für eine Funktion, die das Gegenteil bewirkt.

Die Lösung sollte in C # sein.


15
WARNUNG : Die aus der akzeptierten Antwort resultierenden Ganzzahlen sind falsch , da die IP-Adressen in der Netzwerkreihenfolge (Big-Endian) vorliegen, während ints auf den meisten Systemen Little-Endian sind. Sie müssen also die Bytes vor dem Konvertieren umkehren. Siehe meine Antwort für korrekte Konvertierungen. Auch für IPv4 intkönnen keine Adressen gespeichert werden 127.255.255.255, die größer als z. B. die Broadcast-Adresse sind. Verwenden Sie daher a uint.
Saeb Amini

Antworten:


137

32-Bit-Ganzzahlen ohne Vorzeichen sind IPv4-Adressen. Während die IPAddress.AddressEigenschaft veraltet ist, ist sie eine Int64, die den vorzeichenlosen 32-Bit-Wert der IPv4-Adresse zurückgibt (der Haken ist, dass sie in der Reihenfolge der Netzwerkbytes vorliegt, sodass Sie sie austauschen müssen).

Zum Beispiel ist meine lokale google.com bei 64.233.187.99. Das entspricht:

64*2^24 + 233*2^16 + 187*2^8 + 99
= 1089059683

Und in der Tat, http: // 1089059683 / funktioniert wie erwartet (zumindest unter Windows, getestet mit IE, Firefox und Chrome; funktioniert jedoch nicht auf dem iPhone).

Hier ist ein Testprogramm, um beide Konvertierungen anzuzeigen, einschließlich des Austauschs von Netzwerk- / Host-Bytes:

using System;
using System.Net;

class App
{
    static long ToInt(string addr)
    {
        // careful of sign extension: convert to uint first;
        // unsigned NetworkToHostOrder ought to be provided.
        return (long) (uint) IPAddress.NetworkToHostOrder(
             (int) IPAddress.Parse(addr).Address);
    }

    static string ToAddr(long address)
    {
        return IPAddress.Parse(address.ToString()).ToString();
        // This also works:
        // return new IPAddress((uint) IPAddress.HostToNetworkOrder(
        //    (int) address)).ToString();
    }

    static void Main()
    {
        Console.WriteLine(ToInt("64.233.187.99"));
        Console.WriteLine(ToAddr(1089059683));
    }
}

2
In Opera 11 unter Ubuntu Linux 10.04 bestätigt: Es konvertiert das int zurück in die bekannte wxyz-Form und es funktioniert.
Piskvor verließ das Gebäude

6
IPAddress.Address ist ab .Net 4.0 veraltet .
Erik Philips

@ErikPhilips Ist das wichtig, wenn Sie nur IPv4 verwenden?
Ray

Das ist eine architektonische Entscheidung. Es hat Vor- und Nachteile, und Kommentare sind nicht der beste Ort, um dieses spezielle Thema zu diskutieren.
Erik Philips

1
Sie können BitConverter.ToUInt32 (IPAddress.Parse (Wert) .GetAddressBytes (). Reverse (). ToArray () verwenden, um IPAddress.Address ist veraltet
Mhmd

43

Hier sind zwei Methoden zum Konvertieren von IPv4 in eine korrekte Ganzzahl und zurück:

public static uint ConvertFromIpAddressToInteger(string ipAddress)
{
    var address = IPAddress.Parse(ipAddress);
    byte[] bytes = address.GetAddressBytes();

    // flip big-endian(network order) to little-endian
    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(bytes);
    }

    return BitConverter.ToUInt32(bytes, 0);
}

public static string ConvertFromIntegerToIpAddress(uint ipAddress)
{
    byte[] bytes = BitConverter.GetBytes(ipAddress);

    // flip little-endian to big-endian(network order)
    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(bytes);
    }

    return new IPAddress(bytes).ToString();
}

Beispiel

ConvertFromIpAddressToInteger("255.255.255.254"); // 4294967294
ConvertFromIntegerToIpAddress(4294967294); // 255.255.255.254

Erläuterung

IP-Adressen sind in der Netzwerkreihenfolge (Big-Endian), während ints unter Windows Little-Endian sind. Um einen korrekten Wert zu erhalten, müssen Sie die Bytes umkehren, bevor Sie sie auf einem Little-Endian-System konvertieren.

Auch selbst für IPv4eine intnicht halten können Adressen größer als 127.255.255.255zB die Broadcast - Adresse (255.255.255.255), so verwendet ein uint.


Dies scheint unter Windows mit .NET keinen Unterschied zu machen - unsicher über Mono. Siehe dotnetfiddle.net/cBIOj2
Jesse

2
@Jesse es macht keinen Unterschied für Ihre Eingabe von, 1.1.1.1weil sein Byte-Array palindromisch ist. Versuchen Sie es mit nicht palindromischen wie 127.0.0.1oder 192.168.1.1.
Saeb Amini

Ich sehe das Problem. Wiederholte Zahlen wie 1.1.1.1, 2.2.2.2, 123.123.123.123ergeben immer das gleiche Ergebnis. Für die Nachwelt siehe aktualisierte Geige: dotnetfiddle.net/aR6fhc
Jesse

Ich möchte darauf hinweisen, dass ich verwenden musste System.Net.IPAddress, um dies zum Laufen zu bringen. Funktioniert super!
Shrout1

1
@ Jesse, das wäre nicht nur zum Wiederholen von Zahlen, sondern für alle palindromischen IP-Adressen. Das 2.1.1.2wäre auch so.
Saeb Amini

40

@Barry Kelly und @Andrew Hare, eigentlich denke ich nicht, dass Multiplikation der klarste Weg ist, dies zu tun (obwohl richtig).

Eine Int32 "formatierte" IP-Adresse kann als die folgende Struktur angesehen werden

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct IPv4Address
{
   public Byte A;
   public Byte B;
   public Byte C;
   public Byte D;
} 
// to actually cast it from or to an int32 I think you 
// need to reverse the fields due to little endian

Um die IP-Adresse 64.233.187.99 zu konvertieren, können Sie Folgendes tun:

(64  = 0x40) << 24 == 0x40000000
(233 = 0xE9) << 16 == 0x00E90000
(187 = 0xBB) << 8  == 0x0000BB00
(99  = 0x63)       == 0x00000063
                      ---------- =|
                      0x40E9BB63

Sie können sie also mit + addieren oder binairy oder sie zusammen verwenden. Das Ergebnis ist 0x40E9BB63 (1089059683). (Meiner Meinung nach ist es viel einfacher, die Bytes zu sehen, wenn man in Hex schaut.)

Sie können die Funktion also wie folgt schreiben:

int ipToInt(int first, int second, 
    int third, int fourth)
{
    return (first << 24) | (second << 16) | (third << 8) | (fourth);
}

1
Ich glaube, dass IPs so spezifiziert wurden, um ein solches Verhalten spezifisch zu berücksichtigen ... Bitverschiebungen sind auf den meisten Mikroprozessoren viel effizienter als Mul und Adds.
Ape-inago

1
@ Ape-inago-Multiplikationen mit konstanten Zweierpotenzen werden normalerweise in Bitverschiebungen optimiert, fwiw.
Barry Kelly

Anstelle der Bitverschiebung können Sie die Reihenfolge, in der die Bytes gespeichert sind, verwenden LayoutKind.Explicitund FieldOffsetumkehren. Das funktioniert natürlich nur für die Little-Endian-Architektur. Beispiel auf Github .
RubberDuck

2
Haben Sie darauf hinweist , dass intso signiert ist , wenn Sie 192 um 24 Bits verschoben werden Sie negative ganze Zahl erhalten , also dieser Code für hohe Oktett mit hohem Bit an erster Stelle gebrochen.
Mateusz

12

Probieren Sie diese aus:

private int IpToInt32(string ipAddress)
{
   return BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes().Reverse().ToArray(), 0);
}

private string Int32ToIp(int ipAddress)
{
   return new IPAddress(BitConverter.GetBytes(ipAddress).Reverse().ToArray()).ToString();
}

Reverse()Gibt void zurück, sodass Sie es nicht aufrufen ToArray()können (für zukünftige Leser). Weisen Sie stattdessen den umgekehrten Bytes einen Wert zu, und rufen Sie ToArray () auf.
Erik Philips

1
Reverse () ist die Erweiterungsmethode von IEnumerable. Der obige Code ist vollkommen in Ordnung.
Ameise

3
Diese Methode liefert negative Zahlen für bestimmte IPs (z. B. 140.117.0.0)
lightxx

7

Da niemand den Code gepostet hat, der BitConverterdie Endianness verwendet und tatsächlich überprüft, geht es so weiter:

byte[] ip = address.Split('.').Select(s => Byte.Parse(s)).ToArray();
if (BitConverter.IsLittleEndian) {
  Array.Reverse(ip);
}
int num = BitConverter.ToInt32(ip, 0);

und zurück:

byte[] ip = BitConverter.GetBytes(num);
if (BitConverter.IsLittleEndian) {
  Array.Reverse(ip);
}
string address = String.Join(".", ip.Select(n => n.ToString()));

2
Sie müssen eine Uint verwenden, aber dies ist hier die richtigste Antwort.
RubberDuck

1
@RubberDuck: Sie müssen nur eine verwenden, uintwenn Sie die 32 Datenbits als vorzeichenlose Zahl möchten, intund kann dieselben Informationen speichern . Wenn Sie es in einer Datenbank speichern möchten und intbesser geeignet sind, benötigen Sie eine bigint, um es in der nicht signierten Form speichern zu können.
Guffa

1
Ein Uint ist eine bessere Darstellung IMO. Ein signiertes int benötigt etwas für das Zeichen, sodass Sie Adressen ganz oben im Bereich verlieren. Ja, es kann dieselben Daten enthalten, es wird jedoch als negative Zahl ausgegeben. Dies ist keine gültige IP, wenn Sie sie in die Adressleiste eingeben.
RubberDuck

@RubberDuck: In Form eines können uintSie es auch nicht in die Adressleiste eingeben , Sie müssen es zuerst in eine Textform konvertieren, um dies zu tun. Nur weil die Verwendung der einfachsten Form der Umwandlung eines intTextes keine funktionierende IP-Adresse erzeugt, ist dies kein gutes Argument dafür, sie nicht zu verwenden.
Guffa

@ RubberDuck: Das ist keine uint, das ist die Textdarstellung einer uint.
Guffa

7

Ich habe einige Probleme mit den beschriebenen Lösungen festgestellt, wenn ich IP-Adressen mit einem sehr großen Wert gegenüberstehe. Das Ergebnis wäre, dass das Byte [0] * 16777216-Ding überläuft und zu einem negativen int-Wert wird. Was es für mich behoben hat, ist die einfache Art des Gießvorgangs.

public static long ConvertIPToLong(string ipAddress)
{
    System.Net.IPAddress ip;

    if (System.Net.IPAddress.TryParse(ipAddress, out ip))
    {
        byte[] bytes = ip.GetAddressBytes();

        return
            16777216L * bytes[0] +
            65536 * bytes[1] +
            256 * bytes[2] +
            bytes[3]
            ;
    }
    else
        return 0;
}

scheint mir die beste Lösung zu sein, aber ich würde 1 Zeile ändern, ich würde byte [] bytes = ip.MapToIPv4 (). GetAddressBytes ();
Walter Vehoeven

4

Die Umkehrung von Davy Landmans Funktion

string IntToIp(int d)
{
  int v1 = d & 0xff;
  int v2 = (d >> 8) & 0xff;
  int v3 = (d >> 16) & 0xff;
  int v4 = (d >> 24);
  return v4 + "." + v3 + "." + v2 + "." + v1;
}

Könntest du mehr darüber erklären?
Developerium

3

Meine Frage war geschlossen, ich habe keine Ahnung warum. Die akzeptierte Antwort hier ist nicht die gleiche wie das, was ich brauche.

Dies gibt mir den richtigen ganzzahligen Wert für eine IP.

public double IPAddressToNumber(string IPaddress)
{
    int i;
    string [] arrDec;
    double num = 0;
    if (IPaddress == "")
    {
        return 0;
    }
    else
    {
        arrDec = IPaddress.Split('.');
        for(i = arrDec.Length - 1; i >= 0 ; i = i -1)
            {
                num += ((int.Parse(arrDec[i])%256) * Math.Pow(256 ,(3 - i )));
            }
        return num;
    }
}

Solange Sie die Konvertierung in beide Richtungen durchführen können, verstehe ich nicht, warum die Ausgabenummer korrekt sein muss, solange sie konsistent ist.
GateKiller

Hängt davon ab, wofür Sie die Nummer verwenden möchten. Sie können die andere Konvertierung nicht verwenden, um eine> = und <= Abfrage
durchzuführen

2

Mit dem UInt32 im richtigen Little-Endian-Format gibt es zwei einfache Konvertierungsfunktionen:

public uint GetIpAsUInt32(string ipString)
{
    IPAddress address = IPAddress.Parse(ipString);

    byte[] ipBytes = address.GetAddressBytes();

    Array.Reverse(ipBytes);

    return BitConverter.ToUInt32(ipBytes, 0);
}

public string GetIpAsString(uint ipVal)
{
    byte[] ipBytes = BitConverter.GetBytes(ipVal);

    Array.Reverse(ipBytes);

    return new IPAddress(ipBytes).ToString();
}

2

Mehrere der oben genannten Antworten wurden zu einer Erweiterungsmethode zusammengefasst, die die Endianness des Computers und IPv4-Adressen behandelt, die IPv6 zugeordnet wurden.

public static class IPAddressExtensions
{
    /// <summary>
    /// Converts IPv4 and IPv4 mapped to IPv6 addresses to an unsigned integer.
    /// </summary>
    /// <param name="address">The address to conver</param>
    /// <returns>An unsigned integer that represents an IPv4 address.</returns>
    public static uint ToUint(this IPAddress address)
    {
        if (address.AddressFamily == AddressFamily.InterNetwork || address.IsIPv4MappedToIPv6)
        {
            var bytes = address.GetAddressBytes();
            if (BitConverter.IsLittleEndian)
                Array.Reverse(bytes);

            return BitConverter.ToUInt32(bytes, 0);
        }
        throw new ArgumentOutOfRangeException("address", "Address must be IPv4 or IPv4 mapped to IPv6");
    }
}

Unit Tests:

[TestClass]
public class IPAddressExtensionsTests
{
    [TestMethod]
    public void SimpleIp1()
    {
        var ip = IPAddress.Parse("0.0.0.15");
        uint expected = GetExpected(0, 0, 0, 15);
        Assert.AreEqual(expected, ip.ToUint());
    }
    [TestMethod]
    public void SimpleIp2()
    {
        var ip = IPAddress.Parse("0.0.1.15");
        uint expected = GetExpected(0, 0, 1, 15);
        Assert.AreEqual(expected, ip.ToUint());
    }
    [TestMethod]
    public void SimpleIpSix1()
    {
        var ip = IPAddress.Parse("0.0.0.15").MapToIPv6();
        uint expected = GetExpected(0, 0, 0, 15);
        Assert.AreEqual(expected, ip.ToUint());
    }
    [TestMethod]
    public void SimpleIpSix2()
    {
        var ip = IPAddress.Parse("0.0.1.15").MapToIPv6();
        uint expected = GetExpected(0, 0, 1, 15);
        Assert.AreEqual(expected, ip.ToUint());
    }
    [TestMethod]
    public void HighBits()
    {
        var ip = IPAddress.Parse("200.12.1.15").MapToIPv6();
        uint expected = GetExpected(200, 12, 1, 15);
        Assert.AreEqual(expected, ip.ToUint());
    }
    uint GetExpected(uint a, uint b, uint c, uint d)
    {
        return
            (a * 256u * 256u * 256u) +
            (b * 256u * 256u) +
            (c * 256u) +
            (d);
    }
}

1

Wenn Sie an der Funktion interessiert waren, lautet die Antwort hier nicht nur:

int ipToInt(int first, int second, 
    int third, int fourth)
{
    return Convert.ToInt32((first * Math.Pow(256, 3))
        + (second * Math.Pow(256, 2)) + (third * 256) + fourth);
}

mit firstdurch fourthsind die Segmente der IPv4-Adresse.


1
Ich denke, es wäre klarer, wenn Sie Shift anstelle von Math.Pow verwenden würden.
Mehrdad Afshari

Dies löst eine Überlaufausnahme aus, wenn zuerst> 127 lautet. Davy Landmans Antwort ist der beste Weg, dies zu tun.
Mhenry1384

int32 ist signiert und gibt einen negativen Wert> 127 für das erste Oktett zurück
Mateusz

1
public bool TryParseIPv4Address(string value, out uint result)
{
    IPAddress ipAddress;

    if (!IPAddress.TryParse(value, out ipAddress) ||
        (ipAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork))
    {
        result = 0;
        return false;
    }

    result = BitConverter.ToUInt32(ipAddress.GetAddressBytes().Reverse().ToArray(), 0);
    return true;
}

1
    public static Int32 getLongIPAddress(string ipAddress)
    {
        return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
    }

Das obige Beispiel wäre der Weg, den ich gehe. Möglicherweise müssen Sie nur zu Anzeigezwecken oder zu Zeichenfolgenzwecken in eine UInt32 konvertieren, einschließlich der Verwendung als lange Adresse in Zeichenfolgenform.

Welches ist, was benötigt wird, wenn die IPAddress.Parse (String) -Funktion verwendet wird. Seufzer.


0

Hier ist eine Lösung, die ich heute ausgearbeitet habe (hätte zuerst googeln sollen!):

    private static string IpToDecimal2(string ipAddress)
    {
        // need a shift counter
        int shift = 3;

        // loop through the octets and compute the decimal version
        var octets = ipAddress.Split('.').Select(p => long.Parse(p));
        return octets.Aggregate(0L, (total, octet) => (total + (octet << (shift-- * 8)))).ToString();
    }

Ich verwende LINQ, Lambda und einige der Erweiterungen für Generika. Während es das gleiche Ergebnis liefert, werden einige der neuen Sprachfunktionen verwendet, und Sie können dies in drei Codezeilen tun.

Ich habe die Erklärung auf meinem Blog, wenn Sie interessiert sind.

Prost, -jc


0

Ich denke, das ist falsch: "65536" ==> 0.0.255.255 "Sollte sein:" 65535 "==> 0.0.255.255" oder "65536" ==> 0.1.0.0 "


0

@ Dave Ladman Ihre Lösung mit Shift ist korrekt, aber nur für IP, die mit einer Zahl von weniger oder gleich 99 beginnen, muss der erste Oktekt tatsächlich zu lang sein.

Auf jeden Fall ist das Zurückkonvertieren mit langem Typ ziemlich schwierig, da 64 Bit (nicht 32 für Ip) gespeichert und 4 Bytes mit Nullen gefüllt werden

static uint ToInt(string addr)
{
   return BitConverter.ToUInt32(IPAddress.Parse(addr).GetAddressBytes(), 0);
}

static string ToAddr(uint address)
{
    return new IPAddress(address).ToString();
}

Genießen!

Massimo


0

Angenommen, Sie haben eine IP-Adresse im Zeichenfolgenformat (z. B. 254.254.254.254).

string[] vals = inVal.Split('.');
uint output = 0;
for (byte i = 0; i < vals.Length; i++) output += (uint)(byte.Parse(vals[i]) << 8 * (vals.GetUpperBound(0) - i));

0
var ipAddress = "10.101.5.56";

var longAddress = long.Parse(string.Join("", ipAddress.Split('.').Select(x => x.PadLeft(3, '0'))));

Console.WriteLine(longAddress);

Ausgabe: 10101005056


0
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);

Die GetAddressBytes-Methode gibt die Bytes möglicherweise in umgekehrter Reihenfolge zurück, je nachdem, ob es sich bei der Maschine um Endian oder Endian handelt. Daher kann die richtige Anweisung für einige Maschinen lauten: long m_Address = (Adresse [0] << 24 | Adresse [1] << 16 | Adresse [2] << 8 | Adresse [3]) & 0x0FFFFFFFF
MiguelSlv

0

Ich habe festgestellt, dass System.Net.IPAddress über die Address-Eigenschaft (System.Int64) und den Konstruktor verfügt, die auch den Int64-Datentyp akzeptieren. Sie können dies also verwenden, um die IP-Adresse in das numerische Format (obwohl nicht Int32, sondern Int64) zu konvertieren.


-1

Schauen Sie sich einige der verrückten Parsing-Beispiele in .Nets IPAddress.Parse an: ( MSDN )

65536 ==> 0.0.255.255
20.2 ==> 20.0.0.2
20.65535 ==> 20.0.255.255
128.1.2 ==> 128.1.0.2


Dies ist keine wirkliche Antwort. Warum nicht als Kommentar zu einer der Top-Antworten?
DanM7
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.