在 IPv4
下,我一直将 IP 地址的字符串表示解析为 Int32
并将其作为 SQL Server
中的 INT
存储。
现在,对于 IPv6
,我想知道是否有标准或被接受的方法来使用 C#
将字符串表示的 IPv6
解析为两个 Int64
?
此外,人们如何将这些值存储在 SQL Server
中 - 是作为两个 BIGINT
字段吗?
在 IPv4
下,我一直将 IP 地址的字符串表示解析为 Int32
并将其作为 SQL Server
中的 INT
存储。
现在,对于 IPv6
,我想知道是否有标准或被接受的方法来使用 C#
将字符串表示的 IPv6
解析为两个 Int64
?
此外,人们如何将这些值存储在 SQL Server
中 - 是作为两个 BIGINT
字段吗?
IPv6地址实际上是一个128位的数字,就像IPv4地址实际上是一个32位的数字一样。有不同的地址字符串表示方式,但实际的地址是数字,而不是字符串。
因此,您不需要将IP地址转换为数字,而是需要将地址的字符串表示解析成实际的地址。
甚至连十进制
都无法容纳128位的数字,因此只剩下三种明显的选择:
bigint
字段进行存储varchar
字段中存储地址的字符串表示binary
字段中存储数值这些存储方式都没有像在int
中存储IPv4地址那样方便,因此您必须考虑它们的限制以及您需要对地址执行的操作。
最简单的方法是让框架为您执行此操作。使用IPAddress.Parse
解析地址,然后使用IPAddress.GetAddressBytes
以byte[]形式获取“数字”。
最后,将数组分成前8个字节和后8个字节进行转换为两个Int64,例如通过创建一个MemoryStream
在字节数组上并通过BinaryReader
进行读取。
这样就避免了需要理解所有可用的IPv6地址快捷表示法。
uniqueidentifier
类型。该类型可存储16个字节,非常适合IPv6 IP地址。您可以通过使用构造函数和ToByteArray
在IPAddress
和Guid
之间进行转换。我使用以下方法将IP地址转换为两个UInt64
(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;
}
UInt64
放入数据库之前将其转换为 Int64
,否则会出现 ArgumentException
。当您取回值时,可以将它们转换回 UInt64
以获取无符号值。UInt64[2]
转换为 IP 字符串),因此我从未构建过该方法。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']);