在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