在IPv4
下,我一直在解析IP地址的字符串表示为Int32
并将它们作为INT
存储在SQL Server
中。在C#中将IPv6格式化为int,并将其存储在SQL Server中
现在,使用IPv6
我试图找出是否存在标准或可接受的方式来使用C#
解析IPv6
的两个Int64
的字符串表示形式?
此外,人们如何将这些值存储在SQL Server
中 - 作为BIGINT
的两个字段?
在IPv4
下,我一直在解析IP地址的字符串表示为Int32
并将它们作为INT
存储在SQL Server
中。在C#中将IPv6格式化为int,并将其存储在SQL Server中
现在,使用IPv6
我试图找出是否存在标准或可接受的方式来使用C#
解析IPv6
的两个Int64
的字符串表示形式?
此外,人们如何将这些值存储在SQL Server
中 - 作为BIGINT
的两个字段?
正如IPv4地址确实是一个32位数字,IPv6地址实际上是一个128位数字。地址有不同的字符串表示形式,但实际地址是数字,而不是字符串。
因此,您不会将IP地址转换为数字,而是将地址的字符串表示形式解析为实际地址。
甚至没有一个decimal
可以容纳128位的数字,使叶片三个明显的替代品:
bigint
领域varchar
字段binary
字段ñ要么就像在int
中存储IPv4地址一样方便,所以您必须考虑它们与您需要对地址做什么的限制。
最简单的路线是让框架为你做这件事。使用IPAddress.Parse
解析地址,然后使用IPAddress.GetAddressBytes
以“byte”[]的形式获取“number”。
最后,将数组分成第一个和第二个8个字节,以便转换为两个Int64,例如,通过在字节数组上创建一个MemoryStream
,然后通过BinaryReader
读取。
这样可以避免需要了解IPv6地址的所有可用捷径表示。
我使用以下方法将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
s到Int64
是你把它们放到数据库之前,或者你会得到一个ArgumentException
。当你将值返回时,你可以将它们转换回UInt64
以获得无符号值。
我没有必要做相反的事情(即将UInt64[2]
转换为IP字符串),所以我从来没有为它建立过一个方法。
如果您使用的是SQL Server 2005,则可以使用uniqueidentifier
类型。该类型存储16个字节,非常适合IPv6 IP地址。您可以使用构造函数和ToByteArray
在IPAddress
和Guid
之间进行转换。
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']);
@Bill:你错了。没有什么说您必须将IPv4地址的字节存储为无符号值。 Int32有32位,就像UInt32一样,所以它可以很好地存储4个字节。 – Guffa 2009-10-29 22:20:28
好东西@RBarryYoung没有找到这个线程;-) http://stackoverflow.com/a/1385701/215068 IPv4是4字节的二进制文件,而不是“真正的32位数字”。四个三位八位组只是一个方便的符号 – EBarr 2012-03-30 19:46:50
@EBarr:不,版本4 *中的IP地址是* 32位数字,它不是4字节数字。查看IP数据包的描述,并且您看到地址是32位的单个单元,它们没有分成4个8位值。 – Guffa 2012-03-30 20:04:09