Formatieren von IPv6 als int in C# und speichern Sie es in SQL Server
-
13-09-2019 - |
Frage
Unter IPv4
Ich habe die String -Darstellung von IP -Adressen an Parsen analysiert Int32
und sie speichern als INT
in dem SQL Server
.
Jetzt mit IPv6
Ich versuche herauszufinden, ob es einen Standard oder eine akzeptierte Möglichkeit gibt, die String -Darstellung von zu analysieren IPv6
zu zwei Int64
Verwendung C#
?
Auch wie speichern Menschen diese Werte in der SQL Server
- als zwei Felder von BIGINT
?
Lösung
Da eine IPv4 -Adresse wirklich eine 32 -Bit -Nummer ist, ist eine IPv6 -Adresse wirklich eine 128 -Bit -Nummer. Es gibt unterschiedliche Zeichenfolge Darstellungen der Adressen, aber die tatsächliche Adresse ist die Nummer, nicht die Zeichenfolge.
Sie konvertieren also keine IP -Adresse in eine Nummer, Sie analysieren eine String -Darstellung der Adresse in die tatsächliche Adresse.
Nicht einmal a decimal
kann eine 128 -Bit -Zahl halten, so dass drei offensichtliche Alternativen hinterlassen werden:
- Speichern Sie den numerischen Wert aufgeteilt in zwei
bigint
Felder - Speichern Sie eine String -Darstellung der Adresse in a
varchar
aufstellen - Speichern Sie den numerischen Wert in einem 16 -Byte
binary
aufstellen
Weder ist so bequem wie das Speichern einer IPv4 -Adresse in einem int
, Sie müssen also ihre Grenzen mit dem, was Sie mit den Adressen tun müssen, berücksichtigen.
Andere Tipps
Die einfachste Route besteht darin, den Rahmen für Sie zu tun. Verwenden IPAddress.Parse
dann die Adresse analysieren, dann IPAddress.GetAddressBytes
um die "Nummer" als Byte [] zu erhalten.
Schließlich teilen MemoryStream
über dem Byte -Array und dann über a lesen BinaryReader
.
Dadurch wird vermieden, dass alle verfügbaren Abkürzungen für IPv6 -Adressen verstehen müssen.
Wenn Sie SQL Server 2005 verwenden, können Sie die verwenden uniqueidentifier
Typ. Dieser Typ speichert 16 Bytes, was perfekt für eine IPv6 -IP -Adresse ist. Sie können zwischeneinander konvertieren IPAddress
und Guid
durch Verwendung der Konstrukteure und ToByteArray
.
Ich verwende die folgende Methode zum Konvertieren einer IP -Adresse in zwei UInt64
S (C# 3.0).
/// <summary>
/// Converts an IP address to its UInt64[2] equivalent.
/// For an IPv4 address, the first element will be 0,
/// and the second will be a UInt32 representation of the four bytes.
/// For an IPv6 address, the first element will be a UInt64
/// representation of the first eight bytes, and the second will be the
/// last eight bytes.
/// </summary>
/// <param name="ipAddress">The IP address to convert.</param>
/// <returns></returns>
private static ulong[] ConvertIPAddressToUInt64Array(string ipAddress)
{
byte[] addrBytes = System.Net.IPAddress.Parse(ipAddress).GetAddressBytes();
if (System.BitConverter.IsLittleEndian)
{
//little-endian machines store multi-byte integers with the
//least significant byte first. this is a problem, as integer
//values are sent over the network in big-endian mode. reversing
//the order of the bytes is a quick way to get the BitConverter
//methods to convert the byte arrays in big-endian mode.
System.Collections.Generic.List<byte> byteList = new System.Collections.Generic.List<byte>(addrBytes);
byteList.Reverse();
addrBytes = byteList.ToArray();
}
ulong[] addrWords = new ulong[2];
if (addrBytes.Length > 8)
{
addrWords[0] = System.BitConverter.ToUInt64(addrBytes, 8);
addrWords[1] = System.BitConverter.ToUInt64(addrBytes, 0);
}
else
{
addrWords[0] = 0;
addrWords[1] = System.BitConverter.ToUInt32(addrBytes, 0);
}
return addrWords;
}
Stellen Sie sicher, dass Sie Ihre werfen UInt64
s zu Int64
s, bevor Sie sie in die Datenbank einfügen, oder Sie erhalten eine ArgumentException
. Wenn Sie Ihre Werte wieder herausholen, können Sie sie zurückwerfen UInt64
um den nicht signierten Wert zu erhalten.
Ich muss nicht umgekehrt sein (dh konvertieren a UInt64[2]
zu einer IP -Zeichenfolge) also habe ich nie eine Methode dafür erstellt.
function encode_ip ($ip)
{
return bin2hex(inet_pton($ip));
}
function decode_ip($ip)
{
function hex2bin($temp) {
$data="";
for ($i=0; $i < strlen($temp); $i+=2) $data.=chr(hexdec(substr($temp,$i,2)));
return $data;
}
return inet_ntop(hex2bin($ip));
}
-- max len row db
echo strlen(inet_pton('2001:db8:85a3::8a2e:370:7334'));
-- db row info
ip varchar(16)
-- sql binary save and read
save base
$bin_ip='0x'.bin2hex(inet_pton($data['ip_address']));
-- db read
select ip_address from users;
-- encode binary from db
echo inet_ntop($row['ip_address']);