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.
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.
Antworten:
32-Bit-Ganzzahlen ohne Vorzeichen sind IPv4-Adressen. Während die IPAddress.Address
Eigenschaft 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));
}
}
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 int
s 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 IPv4
eine int
nicht halten können Adressen größer als 127.255.255.255
zB die Broadcast - Adresse (255.255.255.255)
, so verwendet ein uint
.
1.1.1.1
weil sein Byte-Array palindromisch ist. Versuchen Sie es mit nicht palindromischen wie 127.0.0.1
oder 192.168.1.1
.
1.1.1.1
, 2.2.2.2
, 123.123.123.123
ergeben immer das gleiche Ergebnis. Für die Nachwelt siehe aktualisierte Geige: dotnetfiddle.net/aR6fhc
System.Net.IPAddress
, um dies zum Laufen zu bringen. Funktioniert super!
2.1.1.2
wäre auch so.
@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);
}
LayoutKind.Explicit
und FieldOffset
umkehren. Das funktioniert natürlich nur für die Little-Endian-Architektur. Beispiel auf Github .
int
so 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.
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.
IEnumerable
. Der obige Code ist vollkommen in Ordnung.
Da niemand den Code gepostet hat, der BitConverter
die 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()));
uint
wenn Sie die 32 Datenbits als vorzeichenlose Zahl möchten, int
und kann dieselben Informationen speichern . Wenn Sie es in einer Datenbank speichern möchten und int
besser geeignet sind, benötigen Sie eine bigint
, um es in der nicht signierten Form speichern zu können.
uint
Sie 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 int
Textes keine funktionierende IP-Adresse erzeugt, ist dies kein gutes Argument dafür, sie nicht zu verwenden.
uint
, das ist die Textdarstellung einer uint
.
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;
}
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;
}
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;
}
}
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();
}
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);
}
}
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 first
durch fourth
sind die Segmente der IPv4-Adresse.
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;
}
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.
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
Ich denke, das ist falsch: "65536" ==> 0.0.255.255 "Sollte sein:" 65535 "==> 0.0.255.255" oder "65536" ==> 0.1.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
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
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.
int
s 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 IPv4int
können keine Adressen gespeichert werden127.255.255.255
, die größer als z. B. die Broadcast-Adresse sind. Verwenden Sie daher auint
.